Chapter 41

Manual Timeline Building

Automated tools (Plaso, Timesketch) excel at scale but sometimes you need a curated, analyst-built timeline: for a court presentation, for stakeholder communication, or when only a handful of key artifacts are relevant. This chapter covers building clean, narrative-quality timelines manually — the kind that go into executive reports.

Scenario

Legal has asked for a clean 12-event timeline of the attack: the initial access, the credential theft, the lateral movement, and the exfiltration — each event with the supporting evidence and source. Plaso has 1.4 million events. You need to distill those into a 12-row timeline that tells the story to a non-technical audience without losing forensic precision. This chapter covers that distillation process.

Manual Timeline Format

  Investigation Timeline — CASE-2026-009
  ═══════════════════════════════════════════════════════════════════

  Columns:
    Timestamp (UTC) | Host | Event | Evidence Source | Notes

  2026-09-17 01:47:22 | FINANCE-SRV01 | Cobalt Strike beacon executed
    Source: Prefetch — svchst.exe.pf (run at 01:47)
    Notes: Located in C:\Windows\Temp\; filename mimics svchost.exe

  2026-09-17 01:47:24 | Firewall | First C2 check-in to 185.220.101.47
    Source: Firewall log — HTTPS egress rule, src FINANCE-SRV01
    Notes: 2 seconds after beacon execution (consistent with CS default)

  2026-09-17 02:13:05 | DC01 | jsmith's credentials used from FINANCE-SRV01
    Source: Event 4624 on DC01 — Network logon Type 3 from 10.10.5.20
    Notes: jsmith is Finance Director with broad file server access

  2026-09-17 02:14:01 | FS01 | Mass file access — Finance Q3 reports
    Source: Event 4663 on FS01 — 847 file accesses by jsmith in 3 minutes
    Notes: Abnormal — jsmith's normal daily access count is 15-20 files

  ...
  (continue through all key events)

Evidence-to-Event Mapping Script

Pythontimeline-builder.py
#!/usr/bin/env python3
"""
Build a curated investigation timeline from CSV exports of individual artifacts.
Combines Plaso CSV, manual notes, and artifact CSVs into a sorted master timeline.
"""
import csv
import json
from datetime import datetime, timezone

TIMELINE_ENTRIES = []

def add_event(timestamp_str, host, description, source, notes="", confidence="HIGH"):
    """Add a manually identified key event to the master timeline."""
    dt = datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
    TIMELINE_ENTRIES.append({
        "datetime":   dt.strftime("%Y-%m-%d %H:%M:%S UTC"),
        "host":       host,
        "description": description,
        "source":     source,
        "notes":      notes,
        "confidence": confidence
    })

# Add manually identified key events
add_event("2026-09-17T01:47:22Z", "FINANCE-SRV01",
    "Cobalt Strike beacon executed (svchst.exe)",
    "Prefetch: C:\\Windows\\Prefetch\\SVCHST.EXE-A1B2C3D4.pf",
    "Filename mimics svchost.exe; located in C:\\Windows\\Temp\\")

add_event("2026-09-17T01:47:24Z", "FINANCE-SRV01",
    "First C2 check-in to 185.220.101.47:443",
    "Firewall log — rule EGRESS_HTTPS; src 10.10.5.20 dst 185.220.101.47",
    "2 second delay post-execution consistent with CS default sleep setting")

add_event("2026-09-17T02:13:05Z", "DC01",
    "jsmith credentials used via network logon from FINANCE-SRV01",
    "Event 4624 on DC01 (EventRecordID 1023847)",
    "Logon Type 3 (network); NTLMSSP authentication; jsmith = Finance Director")

add_event("2026-09-17T02:14:01Z", "FS01",
    "Mass file access — 847 Finance files in 3 minutes",
    "Event 4663 on FS01 — Object Access audit; jsmith account",
    "Accessed \\\\FS01\\Finance\\2026\\Q3\\ — revenue forecasts and customer contracts")

add_event("2026-09-17T02:55:30Z", "FINANCE-SRV01",
    "Staging archive created: C:\\Windows\\Temp\\update.zip (3.1 GB)",
    "MFT record 123458 — creation timestamp; TSK fls output",
    "File deleted at 03:02:14 after upload; partially recovered via icat")

add_event("2026-09-17T02:58:12Z", "Firewall",
    "3.1 GB HTTPS upload to 45.132.10.77 from FINANCE-SRV01",
    "Firewall log + NetFlow (nfdump output)",
    "Second external IP — likely exfiltration staging server distinct from C2")

# Sort and write
TIMELINE_ENTRIES.sort(key=lambda x: x['datetime'])

output_file = "/cases/CASE-2026-009/MASTER-TIMELINE.csv"
with open(output_file, 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=["datetime","host","description","source","notes","confidence"])
    writer.writeheader()
    writer.writerows(TIMELINE_ENTRIES)

print(f"Master timeline: {len(TIMELINE_ENTRIES)} events → {output_file}")

# Also output as formatted text for report
print("\nATTACK TIMELINE")
print("=" * 80)
for e in TIMELINE_ENTRIES:
    print(f"\n{e['datetime']}  {e['host']}")
    print(f"  {e['description']}")
    print(f"  Evidence: {e['source']}")
    if e['notes']:
        print(f"  Notes: {e['notes']}")

The Pivot Technique

In a manual timeline, each event should be a pivot point — it answers the current question and points to the next:

Event identifiedPivot question it raisesWhere to look next
Beacon executed at 01:47How did the beacon get there?MFT creation time = 01:47 but Zone.Identifier = downloaded from internet at 01:45 → phishing delivery
jsmith credentials used at 02:13How did the attacker get jsmith's credentials?Memory — LSASS at time of beacon → jsmith was logged into FINANCE-SRV01 (TS session)
847 files accessed on FS01What specific files were accessed?Event 4663 details — each access logs the full path; build file list for scope assessment
3.1 GB upload at 02:58Is this the only exfiltration event?NetFlow — check all sessions to 45.132.10.77 for full 47-day period; SRUM for bandwidth history

Q & A

Q: How precise should timestamps be in the manual timeline — to the second, or is the minute sufficient?

Use the precision that the evidence actually supports. Event logs and MFT timestamps have second-level precision — use them. Firewall logs are often per-second. NetFlow has per-second start times. So your forensic working document should use second-level precision for each event (it shows rigor and lets you sequence events within the same minute). For the executive summary version, minute-level precision is acceptable and easier to read. The rule: always document the full precision in the evidence record, then round down for presentation. If you write "02:13 UTC" in a report, your notes should show "02:13:05 UTC (Event 4624 on DC01, RecordID 1023847)" — so anyone who questions your timeline can verify the exact source. Court presentations and legal proceedings require exact second-level timestamps with source citations; executive summaries can use minutes.