NIGHTJAR AFTERMATH
Overview
Six forensic artifacts. The flag is split into shards A–F (one per artifact), each hidden with a different technique. Recover all six shards and concatenate in order: A+B+C+D+E+F.
Shard A: DEADROP{six_ → comm_log.pcap (ICMP payload)
Shard B: artifacts_ → workstation.dd (raw disk slack space)
Shard C: one_ → stego_brief.png (blue channel LSB)
Shard D: truth_ → sqlite_db.db (VIEW definition)
Shard E: the_analyst_ → timeline.evtx.b64 (JSON event field)
Shard F: perseveres} → README.txt (whitespace steganography)
Shard A: comm_log.pcap
Open in Wireshark and filter for ICMP:
icmp
Most pings have generic payloads. One packet stands out with Sequence=99.
Click it, inspect the ICMP data field: the payload is the shard in ASCII.
With tshark:
tshark -r comm_log.pcap -Y "icmp.seq == 99" -x
# or
tshark -r comm_log.pcap -Y "icmp" -T fields -e data.text 2>/dev/null | grep DEADROP
Python approach:
from scapy.all import rdpcap, ICMP, Raw
for pkt in rdpcap('comm_log.pcap'):
if pkt.haslayer(ICMP) and pkt.haslayer(Raw):
payload = pkt[Raw].load
if b'DEADROP' in payload:
print(payload)
Shard A: DEADROP{six_
Shard B: workstation.dd
The filesystem shows a system.log file, that's a decoy. The shard is written
directly into raw disk space at offset 10240, outside the normal filesystem area.
# Option 1: strings
strings workstation.dd | grep SLACK
# Output: [SLACK:artifacts_:END]
# Option 2: raw hex search
xxd workstation.dd | grep -A1 "SLACK"
# Option 3: dd
dd if=workstation.dd bs=1 skip=10240 count=64 2>/dev/null | strings
The marker format is [SLACK:<shard>:END].
Shard B: artifacts_
Shard C: stego_brief.png
Standard LSB steganography in the blue channel (same technique as Forensics 2):
from PIL import Image
img = Image.open('stego_brief.png')
pix = img.load()
bits = []
for row in range(img.height):
for col in range(img.width):
bits.append(pix[col, row][2] & 1) # blue LSB
chars = []
for i in range(0, len(bits), 8):
byte = int(''.join(str(b) for b in bits[i:i+8]), 2)
if byte == 0: break
chars.append(chr(byte))
print(''.join(chars))
Shard C: one_
Shard D: sqlite_db.db
The obvious tables (ops_log, assets) don't contain the shard. Run a full
schema dump:
sqlite3 sqlite_db.db .schema
# or
sqlite3 sqlite_db.db .dump
There's a VIEW definition:
CREATE VIEW hidden_assets AS
SELECT * FROM ops_log WHERE notes='truth_'
-- recovery_key:truth_
The shard is both in the WHERE clause and in the SQL comment. Visible in
.schema, in .dump, and in the raw bytes of the file (strings sqlite_db.db | grep truth).
Shard D: truth_
Shard E: timeline.evtx.b64
The file is base64-encoded JSON masquerading as a Windows Event Log export. Strip the comment lines and decode:
grep -v '^#' timeline.evtx.b64 | base64 -d | python3 -m json.tool
Or in Python:
import base64, json
lines = [l for l in open('timeline.evtx.b64') if not l.startswith('#')]
events = json.loads(base64.b64decode(''.join(lines)))
for e in events:
print(json.dumps(e, indent=2))
Look through all events carefully. EventID 4800 ("Workstation locked") has an
unusual field: CorrelationActivityID. Standard Windows events don't have this
field, it's the hiding spot.
{
"EventID": 4800,
"CorrelationActivityID": "the_analyst_",
...
}
Shard E: the_analyst_
Shard F: README.txt
The README itself is Shard F's carrier.
Extract the encoding:
Detect trailing spaces with cat -A (shows $ at line end, $ for trailing space):
cat -A README.txt
# lines ending in ' $' are bit 1, lines ending in '$' are bit 0
Shard F: perseveres}
Assembly
A: DEADROP{six_
B: artifacts_
C: one_
D: truth_
E: the_analyst_
F: perseveres}
Flag: DEADROP{six_artifacts_one_truth_the_analyst_perseveres}
Key Takeaway
Multi-artifact forensics requires breadth as much as depth. Each technique here (network carving, slack space, LSB steg, schema inspection, field enumeration, whitespace encoding) is individually straightforward, the challenge is knowing to apply each one and having the patience to look everywhere.