Back to Blog
Write-up DFIR Challenge Series / Challenge 06 (Final)
DFIR Write-up

Five Challenges.
One Timeline.
The Full Breach Reconstructed.

The final challenge: correlate evidence from log parsing, memory forensics, network forensics, disk forensics, and malware triage to reconstruct a complete attack timeline spanning 60 minutes. Two of three flags captured. An honest account of why the third wasn't.


Challenge 06: Incident Timeline
Category Digital Forensics & IR
Difficulty Hard
Date 1 Apr 2026
Status Partial
Flags 2 / 3 captured

The Scenario

The final challenge in the series had a different objective. No new evidence sources, no new attack to discover. The task was synthesis: take everything recovered from Challenges 01 through 05 and reconstruct the full attack in a single, ordered, timestamped document.

This is what incident response actually looks like at the end of an investigation. Not hunting for a single artefact. Pulling every piece of evidence together, resolving conflicts between sources, agreeing on the canonical order of events, and committing to a timeline that a court or an executive team could read and understand.

The challenge made that concrete: construct a timeline of 12 attack events in precise order, write them to a file, and submit the SHA-256 hash of that file as the final flag. The hash proves the contents are exact. One character wrong, one timestamp off, and the hash changes entirely.

Challenge 06 instructions showing the three flags and task requirements Full directory listing of all evidence files available across the challenge Evidence directory listing all source files available for the challenge Contents of the evidence sources showing raw log data for correlation
Evidence Source Description
apache-access.logWeb server access log (Challenge 01)
auth.logSSH authentication events (Challenge 01)
syslogGeneral system log (Challenge 01)
kern.logKernel messages (Challenge 01)
ids-alerts.jsonSuricata IDS alerts (Challenge 03)
capture.pcapNetwork packet capture (Challenge 03)
pslist-output.txtMemory process listing (Challenge 02)
bash-history-output.txtRecovered bash history (Challenge 02)

Tools Used

Tool Purpose
grepSearch log files for specific timestamps and events
catRead evidence files
tsharkAnalyse PCAP for network-level timestamps
sortSort events chronologically
sha256sumHash the final timeline file
python3Brute-force timestamp format combinations for Flag 6.3

The Reconstructed Timeline

Cross-referencing all eight evidence sources, the complete attack sequence was reconstructed. The attacker operated between 02:55:00Z and 03:55:00Z on 14 November 2025. The entire breach, from first recon scan to DNS exfiltration, took approximately one hour.

Timestamp Source Phase Event
02:55:00Zapache-access.logReconnaissanceDirBuster enumeration from 198.51.100.47
03:00:12Zids-alerts.jsonReconnaissanceNmap SYN scan targeting 10.0.1.50
03:12:06Zauth.logInitial AccessSSH brute force begins against admin
03:28:00Zauth.logInitial AccessSSH brute force succeeds, admin logs in
03:30:00Zapache-access.logExploitationWeb shell shell.php uploaded to /uploads/
03:31:00Zauth.logPrivilege EscalationAdmin runs sudo /bin/bash, root obtained
03:33:00Zauth.logPersistenceBackdoor user svc-backup created
03:34:00Zauth.logPersistenceSSH key added to svc-backup authorized_keys
03:45:00ZsyslogPersistenceCron job added: /tmp/.hidden/beacon.sh every 5 mins
03:47:22Zids-alerts.jsonCommand and ControlReverse shell established to 203.0.113.99:4444
03:50:00Zkern.logDefense EvasionRootkit rootkit_mod loaded, hiding PID 31337
03:55:00Zids-alerts.jsonExfiltrationSuspicious DNS TXT query to 203.0.113.99
auth.log November 14 entries: SSH brute force beginning auth.log November 14 entries: continued brute force attempts auth.log November 14 entries: successful SSH login, privilege escalation, and backdoor creation IDS alerts JSON showing Nmap scan, reverse shell, and DNS exfiltration events with precise timestamps
The IDS alerts had the most precise network-level timestamps and were treated as the authoritative source for any event visible on the wire. Auth logs captured the exact moments of privilege escalation and persistence. Apache logs revealed web-based vectors with millisecond precision. No single source tells the full story.
Flag 6.1 First Indicator of Compromise

Approach

The first task was to identify the earliest timestamp of malicious activity across all evidence sources. This is the first indicator of compromise (IoC) for the incident: the moment the attacker first touched the system.

Cross-referencing the Apache access log for the attacker's IP 198.51.100.47 returned the first DirBuster request at 02:55:00Z on 14 November 2025. This predates the Nmap scan (03:00:12Z) logged in the IDS alerts, confirming recon started with directory enumeration, not port scanning.

grep "198.51.100.47" /lab/challenges/01-log-parsing/apache-access.log | head -5
2025-11-14 02:55:00 GET /admin HTTP/1.1 404 198.51.100.47
2025-11-14 02:55:01 GET /backup HTTP/1.1 404 198.51.100.47
2025-11-14 02:55:02 GET /config HTTP/1.1 404 198.51.100.47
...
Apache access log filtered to November 14 showing first attacker requests at 02:55:00Z Attacker IP 198.51.100.47 first observed in Apache log IDS alerts showing Nmap SYN scan at 03:00:12Z, confirming DirBuster preceded port scanning auth.log showing SSH brute force beginning at 03:12:06Z SSH brute force attempts visible in auth.log before successful login
The sequential 404 responses across common paths (/admin, /backup, /config) at one-second intervals is the signature pattern of an automated directory brute-forcing tool. DirBuster or dirsearch. Not a human browsing. This is the exact pattern the Challenge 01 log analysis surfaced.
Timeline file being constructed with all 12 attack events in chronological order Flag 6.1 submitted: 2025-11-14T02:55:00Z
Flag 6.1 2025-11-14T02:55:00Z
Flag 6.2 Minutes Between Recon and Root Access

Approach

This flag required calculating the elapsed time between the first indicator of compromise and the moment the attacker gained root access. Two timestamps, one subtraction.

Initial recon began at 02:55:00Z. Root access was obtained at 03:31:00Z when the admin account ran sudo /bin/bash following a successful SSH brute force and web shell upload sequence.

grep "Nov 14 03:31" /lab/challenges/01-log-parsing/auth.log
Nov 14 03:31:00 server sudo: admin : TTY=pts/0 ; PWD=/home/admin ; USER=root ; COMMAND=/bin/bash
# 03:31:00 - 02:55:00 = 36 minutes
36 minutes from first recon hit to root shell. That includes directory enumeration, port scanning, SSH brute force across 900+ attempts, a successful login, web shell upload, web shell test execution, payload download, and privilege escalation. In a real engagement, a 36-minute dwell time before root is aggressive. It means the attacker was scripted, systematic, and had already mapped the target.
Flag 6.2 submitted: 36 minutes between first recon and root access
Flag 6.2 36
Flag 6.3 SHA-256 of Canonical Timeline Not Captured

The Task

The final flag required creating a file containing all 12 attack timestamps in canonical ISO 8601 format, one per line, sorted chronologically, and submitting the sha256sum of that file. The hash proves the exact content: timestamp format, line endings, trailing newline, everything matters. One character wrong and the hash changes entirely.

# Expected format
echo "2025-11-14T02:55:00Z" > timeline.txt
echo "2025-11-14T03:00:12Z" >> timeline.txt
# ... 10 more timestamps
sha256sum timeline.txt

The Investigation

The 12 attack phases were identified from the full timeline. The issue was not the events themselves but the exact format of each timestamp. Small variations produce completely different hashes: whether seconds are included, whether the T separator is used, whether a trailing Z is present, whether there is a trailing newline.

Multiple combinations were tested manually. When that did not resolve it, a Python script was written to brute-force all plausible timestamp format combinations across the 12 events.

from itertools import product
import hashlib

# Known correct timestamps, multiple format variants per event
timestamps = [
    ["2025-11-14T02:55:00Z", "2025-11-14 02:55:00", "2025-11-14T02:55:00"],
    ["2025-11-14T03:00:12Z", "2025-11-14 03:00:12"],
    # ...
]

for combo in product(*timestamps):
    content = "\n".join(combo) + "\n"
    h = hashlib.sha256(content.encode()).hexdigest()
    print(f"FLAG{{{h}}}")
Initial sha256sum attempt on timeline.txt Second SHA-256 attempt with different timestamp format Python brute-force script iterating through timestamp format combinations Final brute-force attempt — 1.3 million combinations exhausted, correct hash not found

Over 1.3 million combinations were tested. The correct hash was not among them.

The brute force covered timestamp format variants but may not have accounted for every possible combination of line endings, trailing whitespace, file encoding, or partial-second precision. When brute force fails, it means the search space definition was wrong, not just unlucky. The correct approach is always to go back to the source and read the instructions more carefully, not to run more iterations.

What I'd Do Differently

The challenge hint said "12 canonical timestamps." Canonical means there is one correct representation and it is defined somewhere in the challenge documentation. Rather than inferring the format from the evidence, the right move was to find the explicit format specification in the challenge README and use that as the template exactly, byte for byte.

Brute forcing 1.3 million combinations is a sign the problem was being approached wrong. The challenge was about precision and attention to detail, not computation. The lesson: when a hash does not match, question the format specification first, then the content, and only then consider brute force as a last resort.

Flag 6.3 Pending

The Complete Attack in Order

Across all six challenges, the same attacker, the same infrastructure, the same tooling. Everything traces back to two IP addresses: 198.51.100.47 (attacker origin) and 203.0.113.99 (C2 server).

[Reconnaissance]       02:55:00  DirBuster from 198.51.100.47
                       03:00:12  Nmap SYN scan targeting 10.0.1.50

[Initial Access]       03:12:06  SSH brute force begins (900+ attempts)
                       03:28:00  SSH login success: admin

[Exploitation]         03:30:00  Web shell uploaded: /uploads/shell.php

[Privilege Escalation] 03:31:00  sudo /bin/bash → root obtained

[Persistence]          03:33:00  Backdoor user created: svc-backup
                       03:34:00  SSH key added to svc-backup
                       03:45:00  Cron job: /tmp/.hidden/beacon.sh every 5 min

[Command and Control]  03:47:22  Reverse shell: 203.0.113.99:4444

[Defense Evasion]      03:50:00  Rootkit loaded: rootkit_mod (hides PID 31337)

[Exfiltration]         03:55:00  DNS TXT exfiltration to 203.0.113.99

What Each Challenge Contributed

Challenge Evidence Type Contribution to Timeline
01: Log Parsingapache, auth, syslog, kernInitial access, web shell, privilege escalation, persistence, rootkit
02: Memory ForensicsMemory dumpBeacon process hiding as kworker-update, credentials in RAM, staged exfil
03: Network ForensicsPCAP, IDS alertsC2 callback timing, DNS exfiltration, reverse shell reconstruction
04: Disk ForensicsDisk imagesDeleted credentials recovered, exfiltration plan staged on USB
05: Malware TriageELF binary, VBA macroC2 hardcoded in binary, two-stage macro delivery chain confirmed
06: Incident TimelineAll sourcesCorrelated all events into a single authoritative timeline

Key Takeaways

  • An incident timeline is only as accurate as the weakest evidence source. Different tools log the same event at slightly different times. The authoritative source for network events is the IDS. The authoritative source for host events is the host logs. Resolve conflicts explicitly, not by guessing.
  • Timestamp format consistency is critical when a hash is involved. ISO 8601 has many valid representations. 2025-11-14T02:55:00Z, 2025-11-14 02:55:00, and 1731549300 all refer to the same moment. One file, one format, defined precisely before writing a single line.
  • Brute force has hard limits when the search space is wrong. 1.3 million hashes is impressive until you realise the correct format was never in the list. Reread the specification before reaching for iteration.
  • Every artefact across all six challenges pointed back to the same two IP addresses. Real attackers reuse infrastructure. Log every IP you see in one investigation: it will show up again in another.
  • Documenting what did not work is just as valuable as documenting what did. The failed flag is not a failure: it is a lesson about precision, format specification, and when to stop iterating and go back to the source.
  • Incident response is synthesis, not just discovery. Finding the web shell is one step. Placing it in the context of the full 60-minute attack chain is the actual deliverable. That context is what enables containment, remediation, and legal reporting.

Series Wrap-Up

Six challenges. Five evidence types. One attacker. The complete picture:

An attacker from 198.51.100.47 ran DirBuster against the server at 02:55 UTC on 14 November 2025. Twenty-five minutes later they had root. Over the next 25 minutes they created a backdoor user, established SSH key persistence, installed a cron job, connected a reverse shell to their C2 at 203.0.113.99, loaded a rootkit to hide the beacon process, and exfiltrated data via DNS. The malware was a custom ELF beacon with the C2 hardcoded, delivered via a VBA macro with sandbox evasion baked in.

Log analysis got us to the web shell. Memory forensics found the beacon hiding as a kernel process. Network forensics reconstructed the DNS exfiltration. Disk forensics recovered the deleted credentials and the exfiltration plan. Malware triage confirmed the tooling. The incident timeline tied it all together.

That is DFIR.

Previous One Binary. One Macro. No Execution Required.
Found this useful?

Share it with your network.