Building an event-log timeline for incident response
How to turn scattered .evtx files into one defensible timeline — which events to anchor on, normalising to UTC, correlating across hosts and logs, joining sessions by LogonId, and avoiding the common timelining mistakes.
Individual events answer small questions. A timeline answers the big one: what happened, in what order, across which machines. It is also the deliverable — the artifact an investigation is judged on. This post is how to build one from event logs that holds up, pulling together the threads from across this blog.
Start from the question, not the data
A timeline is scoped by a question: "trace this account from initial access to objective," "what touched this server between Tuesday and Thursday," "how did they persist." Decide the subject (an account, a host, an IP) and the window first — it tells you which logs to pull and keeps the timeline from drowning in noise.
The events worth anchoring on
You rarely need every event. These carry most incident timelines:
| Phase | Anchor events |
|---|---|
| Access | 4624 / 4625 (+ logon type), 4768/4769/4771, 4776 |
| Remote | RDP 1149 / 4624 type 10 / LSM 21 |
| Execution | 4688, Sysmon 1, PowerShell 4104 |
| Privilege | 4672, 4728/4732 |
| Persistence | 4698 / TaskScheduler, 7045, WMI 5861 |
| Anti-forensics | 1102 / 104 |
A rule scan is a good way to find the first anchors; then expand outward in time around each confirmed hit.
Normalise to UTC — first, always
The most common timelining error is mixing time zones. Every EVTX record stores its time as a UTC FILETIME; tools may display local time. Before you merge anything:
- Pin every source to UTC.
- Note each host's clock skew if you have it (a host with a wrong clock will scatter events; record the offset and correct).
- Keep sub-second precision when ordering rapid sequences — record IDs break ties when timestamps collide.
A timeline in mixed local times is worse than no timeline; it invents a sequence that didn't happen.
Correlate across hosts and logs
Real incidents span machines and channels. The joins that matter:
TargetLogonIdties a session together on one host: 4624 → 4672 → activity → 4634/4647. It is the strongest within-host join.- Source IP / account / time tie the DC half (Kerberos/NTLM validation) to the host half (4624) of one logon — see logon events end to end.
- 1024 → 1149 ties the source and destination of an RDP hop across two hosts.
- Account + time ties a logon to the task or group change that logon made.
Pull logs from every host in scope (and the DC), not just the victim — attackers clean the target and forget the controller.
Tools for assembly
- Eric Zimmerman's EvtxECmd → Timeline Explorer. EvtxECmd flattens EVTX (its maps turn EventData into named columns); Timeline Explorer sorts/filters the combined CSV. The IR workhorse.
- Hayabusa csv-timeline for a ranked, cross-file detection timeline (see the tooling post).
- Plaso / log2timeline when you need a super timeline that fuses EVTX with filesystem, registry, and other artifacts into one stream.
- The browser parser for reading a specific file's events and its built-in timeline view when you want to eyeball one log without tooling.
Mind the gaps
A timeline must represent absence honestly:
- Missing expected events. No 4624 for a session you can prove happened = suppressed logging or a cleared log, which is itself a timeline entry.
- Record-ID gaps and a cleared 1102 mark deleted history — annotate the gap; don't silently skip it. The tampering guide covers reading the negative space.
- Rolled logs. The small Operational logs (RDP, TaskScheduler) age out fast; "nothing after date X" may mean the log rolled, not that activity stopped.
A workable process
- Fix the subject and window.
- Collect logs from all in-scope hosts + DC; convert to UTC.
- Scan with Sigma to find anchors.
- For each anchor, pull the surrounding events and join by LogonId / IP / account / 1024→1149.
- Lay the confirmed events on one UTC line; annotate gaps (clears, rolls, missing events).
- Write the narrative the timeline supports — and only what it supports.
A good event-log timeline is mostly discipline: one clock, the right anchors, honest gaps. Get those, and the individual event posts on this blog supply the meaning for each row.