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.
| Evidence Source | Description |
|---|---|
apache-access.log | Web server access log (Challenge 01) |
auth.log | SSH authentication events (Challenge 01) |
syslog | General system log (Challenge 01) |
kern.log | Kernel messages (Challenge 01) |
ids-alerts.json | Suricata IDS alerts (Challenge 03) |
capture.pcap | Network packet capture (Challenge 03) |
pslist-output.txt | Memory process listing (Challenge 02) |
bash-history-output.txt | Recovered bash history (Challenge 02) |
Tools Used
| Tool | Purpose |
|---|---|
grep | Search log files for specific timestamps and events |
cat | Read evidence files |
tshark | Analyse PCAP for network-level timestamps |
sort | Sort events chronologically |
sha256sum | Hash the final timeline file |
python3 | Brute-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:00Z | apache-access.log | Reconnaissance | DirBuster enumeration from 198.51.100.47 |
03:00:12Z | ids-alerts.json | Reconnaissance | Nmap SYN scan targeting 10.0.1.50 |
03:12:06Z | auth.log | Initial Access | SSH brute force begins against admin |
03:28:00Z | auth.log | Initial Access | SSH brute force succeeds, admin logs in |
03:30:00Z | apache-access.log | Exploitation | Web shell shell.php uploaded to /uploads/ |
03:31:00Z | auth.log | Privilege Escalation | Admin runs sudo /bin/bash, root obtained |
03:33:00Z | auth.log | Persistence | Backdoor user svc-backup created |
03:34:00Z | auth.log | Persistence | SSH key added to svc-backup authorized_keys |
03:45:00Z | syslog | Persistence | Cron job added: /tmp/.hidden/beacon.sh every 5 mins |
03:47:22Z | ids-alerts.json | Command and Control | Reverse shell established to 203.0.113.99:4444 |
03:50:00Z | kern.log | Defense Evasion | Rootkit rootkit_mod loaded, hiding PID 31337 |
03:55:00Z | ids-alerts.json | Exfiltration | Suspicious DNS TXT query to 203.0.113.99 |
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
...
/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.
2025-11-14T02:55:00Z
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
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}}}")
Over 1.3 million combinations were tested. The correct hash was not among them.
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.
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 Parsing | apache, auth, syslog, kern | Initial access, web shell, privilege escalation, persistence, rootkit |
| 02: Memory Forensics | Memory dump | Beacon process hiding as kworker-update, credentials in RAM, staged exfil |
| 03: Network Forensics | PCAP, IDS alerts | C2 callback timing, DNS exfiltration, reverse shell reconstruction |
| 04: Disk Forensics | Disk images | Deleted credentials recovered, exfiltration plan staged on USB |
| 05: Malware Triage | ELF binary, VBA macro | C2 hardcoded in binary, two-stage macro delivery chain confirmed |
| 06: Incident Timeline | All sources | Correlated 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, and1731549300all 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.