Chapter 28

TSK Timeline Analysis

The TSK/Mactime timeline combines file system timestamps from MFT entries into a chronological activity log. This chapter covers building a filesystem timeline with fls and mactime, filtering it to investigation windows, and correlating filesystem timestamps with other artifact sources.

Scenario

You need to reconstruct what the attacker did on a server between 02:00 and 06:00 UTC on September 17. The event logs for that period were cleared. Prefetch has partial data. But the MFT timestamps for every file create, modify, and access event during that window are preserved. A TSK timeline for that 4-hour window shows 847 filesystem events — among them, file creations in a temp directory, archive file creation, and then deletions. The timeline doesn't lie even when logs are cleared.

Building the Filesystem Timeline

Bashbuild-tsk-timeline.sh
IMAGE="/cases/CASE-2026-009/FINANCE-SRV01.E01"
OFFSET=2048
CASE_DIR="/cases/CASE-2026-009"

# Step 1: Generate body file (input to mactime)
# fls -m produces mactime-format output: one entry per file per timestamp type
fls -m "C:/" -r -o $OFFSET $IMAGE > $CASE_DIR/body.txt
# -m "C:/": prefix for file paths (label the volume as C:/)
# Output format: MD5|filename|inode|perms|uid|gid|size|atime|mtime|ctime|btime

# Step 2: Generate the timeline (mactime)
mactime -b $CASE_DIR/body.txt -d > $CASE_DIR/timeline-all.csv
# -d: output as CSV (comma-separated)
# Output columns: Date,Size,Type,Mode,UID,GID,Meta,File Name

# Step 3: Filter to investigation window
# Attack window: 2026-09-17 02:00 UTC to 2026-09-17 06:00 UTC
mactime -b $CASE_DIR/body.txt -d \
    -z UTC \
    -i day/2026-09-17 \
    > $CASE_DIR/timeline-sept17.csv

# Or with explicit start/end:
mactime -b $CASE_DIR/body.txt -d -z UTC \
    "2026-09-17 02:00:00" "2026-09-17 06:00:00" \
    > $CASE_DIR/timeline-attack-window.csv

echo "Events in attack window: $(wc -l < $CASE_DIR/timeline-attack-window.csv)"

Understanding the Timeline Output

  TSK/Mactime Timeline Output Format
  ═══════════════════════════════════════════════════════════════════

  Each row = one file + one timestamp type combination

  Date,Size,Type,Mode,UID,GID,Meta,File Name

  Type column letters:
    m = Modified (last write time) — $SI ModTime
    a = Accessed (last access time) — $SI AccessTime
    c = Changed (MFT record change) — $SI MFTModTime
    b = Born (creation time) — $SI CreateTime

  Multiple letters = same timestamp for multiple types
  Example: "macb" = file was created (b), and all 4 timestamps were set
            at the same moment (common for newly created files)

  Example rows:
  Sun Sep 17 2026 02:13:22,1847392,m...,---rwxr-x,0,0,123456,C:/Users/jsmith/AppData/Local/Temp/svchst.exe
  Sun Sep 17 2026 02:13:22,1847392,...b,---rwxr-x,0,0,123456,C:/Users/jsmith/AppData/Local/Temp/svchst.exe
  Sun Sep 17 2026 02:14:01,24576,...b,---rwxr-x,0,0,123457,C:/Users/jsmith/AppData/Local/Temp/beacon.dll
  Sun Sep 17 2026 02:55:30,3271680,...b,---rwxr-x,0,0,123458,C:/Users/jsmith/Desktop/STAGING/data.zip

  Reading the attack progression:
    02:13 — svchst.exe appears (modified + born = written to disk)
    02:14 — beacon.dll appears (born)
    02:55 — data.zip appears (born = archive created)
    → Clear staging/exfiltration prep pattern

Filtering and Pivoting the Timeline

Bashanalyze-timeline.sh
TIMELINE="$CASE_DIR/timeline-attack-window.csv"

# Find executable files created during the window
grep -i "\.exe\|\.dll\|\.ps1\|\.bat\|\.vbs\|\.js" $TIMELINE | \
    grep "\.\.\.b" | \       # born = created
    sort -t, -k1,1 | head -30

# Find large file creation (potential staging/exfiltration archives)
awk -F, '$2 > 1000000' $TIMELINE | grep "\.\.\.b" | sort -t, -k2 -rn | head -20

# Find files in user temp directories
grep -iP "Temp|AppData\\\\Roaming|Desktop" $TIMELINE | \
    grep "\.\.\.b" | sort -t, -k1,1

# Find file deletions (changes without birth = file was deleted or modified)
# Deletion shows as: ctime changes but no birth event
grep "m\.\.c\|\.ac\.\|m\.c\." $TIMELINE | \
    grep -v "\.exe\|\.dll" | \
    sort -t, -k1,1 | tail -50

# Summarize activity by minute — find high-activity moments
awk -F, '{print substr($1,1,16)}' $TIMELINE | sort | uniq -c | sort -rn | head -20

Building a Super-Timeline

A super-timeline combines the TSK/Mactime filesystem timeline with other artifact sources (event logs, registry, browser history) into a single chronological view. This is the foundation of Plaso (covered in Ch39), but you can build a basic version manually:

Bashmanual-super-timeline.sh
CASE_DIR="/cases/CASE-2026-009"
TRIAGE="$CASE_DIR/triage"

# Convert TSK timeline to common format (date, source, description)
awk -F, '{print $1 ",FSTimeline," $8}' $CASE_DIR/timeline-attack-window.csv \
    > $CASE_DIR/super-timeline.csv

# Add event log entries for the same window
# (from EvtxECmd CSV output, filtered to window)
if [ -f "$TRIAGE/evtx/Security.csv" ]; then
    awk -F, '$1 >= "2026-09-17 02:00" && $1 <= "2026-09-17 06:00"' \
        "$TRIAGE/evtx/Security.csv" | \
        awk -F, '{print $1 ",EventLog,Event " $2 " - " $3}' \
        >> $CASE_DIR/super-timeline.csv
fi

# Add Prefetch entries
if [ -f "$TRIAGE/prefetch/PECmd_Output.csv" ]; then
    awk -F, 'NR>1 {
        n=split($3,times,"|")
        for(i=1;i<=n;i++) {
            if (times[i] >= "2026-09-17 02" && times[i] <= "2026-09-17 06")
                print times[i] ",Prefetch,Executed: " $1
        }
    }' "$TRIAGE/prefetch/PECmd_Output.csv" \
    >> $CASE_DIR/super-timeline.csv
fi

# Sort chronologically and output
sort -t, -k1,1 $CASE_DIR/super-timeline.csv > $CASE_DIR/super-timeline-sorted.csv
echo "Super-timeline events: $(wc -l < $CASE_DIR/super-timeline-sorted.csv)"

Timestamp Artifacts to Investigate

Suspicious patternWhat it meansInvestigation step
Executable born at 02:xx UTC on a serverAttacker-dropped tool — servers don't install new programs at 2amExtract file, hash it, submit to VT, correlate with process creation events
Large file born then deleted within minutesStaging archive created and removed — exfiltration stagingAttempt recovery via icat; check SRUM for network bandwidth in the same window
Group of files all share exact same creation timestamp to the secondAttacker batch-dropped a toolkit (e.g., ZIP extracted or robocopy)List all files with that exact timestamp — they're the complete toolkit
SI CreateTime < FN CreateTimeTimestomping — $SI was backdated to appear olderRun MFTECmd SI_LT_FN hunt; compare with parent directory timestamps
MFT record number much higher than expected for file timestampTimestomping — new file (high record number) has old timestampsExtract all records in that MFT range and check for other suspicious files nearby

Q & A

Q: The timeline shows thousands of events even in a 4-hour window. How do you reduce it to what matters?

Apply progressive filters: (1) Start with "born" events only (new file creation) — these are attacker artifacts. Modifications to existing system files are usually legitimate. (2) Filter by path: focus on user home directories, temp folders (%TEMP%, C:\Windows\Temp), and unusual locations like C:\PerfLogs or root directories. Ignore C:\Windows\WinSxS, C:\Windows\System32, and C:\Windows\assembly which have thousands of legitimate entries. (3) Filter by type: focus on .exe, .dll, .ps1, .bat, .vbs, .zip, .7z, .rar. Ignore .log, .tmp, .etl files unless they appear in unusual locations. (4) Look at volume: if 100 events happen within the same 30-second window, they're likely related (a tool extraction). (5) Cross-reference with process creation events — if an executable appears in the filesystem but never in 4688 logs, it was dropped but not yet run (or ran before log clearing).