Skip to content

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.

By Florian AmettePublished 4 {n} min read

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:

PhaseAnchor events
Access4624 / 4625 (+ logon type), 4768/4769/4771, 4776
RemoteRDP 1149 / 4624 type 10 / LSM 21
Execution4688, Sysmon 1, PowerShell 4104
Privilege4672, 4728/4732
Persistence4698 / TaskScheduler, 7045, WMI 5861
Anti-forensics1102 / 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:

  • TargetLogonId ties 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

  1. Fix the subject and window.
  2. Collect logs from all in-scope hosts + DC; convert to UTC.
  3. Scan with Sigma to find anchors.
  4. For each anchor, pull the surrounding events and join by LogonId / IP / account / 1024→1149.
  5. Lay the confirmed events on one UTC line; annotate gaps (clears, rolls, missing events).
  6. 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.

Related posts

A practical workflow for answering 'was there a remote desktop session' from EVTX alone — which logs to pull, which event IDs to filter, how to confirm a real interactive session, and how to read the source and timing.
How real adversary tools move host-to-host in Windows estates, and the precise event ID combinations in Security.evtx that catch PsExec, Impacket, and WMIExec.
How attackers clear Windows event logs, what evidence remains on disk and in forwarded channels, and the difference between wevtutil cl and thread-suspension tools like Invoke-Phant0m.