the_step
Challenge
Imported from local notes.md.
Solution
Original Notes
the_step
Challenge Summary
- Given: An analyzer output file,
starting_files/network_forensics.log, produced from a pcap by an unreliable LLM-based network forensic tool. - Goal: Recover the payload fragments in true chronological order and join them with underscores.
- Constraints: The report itself is out of order and mixes many unrelated flows with the interesting ones.
Initial Recon / Triage
- Observations:
- The log contains many shuffled flow records.
- Most records have
Payload Fragment: -and are noise. - Every non-empty payload fragment belongs to TLS traffic with the same JA3 hash and the same destination IP,
45.76.123.45.
- File identification:
starting_files/network_forensics.log- analyzer flow report.artifacts/ordered_payloads.txt- recovered ordered fragment sequence.
- Entry points:
- Repeated IOC note in the header.
Payload Fragmentfields within the repeated JA3/destination cluster.
Hypotheses & Approach
- Hypothesis 1: The malicious sequence is the repeated TLS JA3 cluster mentioned in the report header.
- Hypothesis 2: The report order is unreliable, but the per-record timestamps are enough to sort the payload fragments chronologically.
Execution Steps (Reproducible)
Stage 1
Commands:
cd /root/dawg2026CTF/the_step
wc -l starting_files/network_forensics.log
rg -n "45\.76\.123\.45|d2b4c6a8f0e1d3c5b7a9f2e4d6c8b0a1" starting_files/network_forensics.log
Results:
- The report is a plain-text flow dump with many records.
- The suspicious cluster consists of repeated TLS flows to
45.76.123.45sharing JA3d2b4c6a8f0e1d3c5b7a9f2e4d6c8b0a1.
Stage 2
Commands:
cd /root/dawg2026CTF/the_step
python3 - <<'PY'
from pathlib import Path
import re
from datetime import datetime
text = Path('starting_files/network_forensics.log').read_text()
rows = []
for block in text.split('--- Flow Record #')[1:]:
ts = re.search(r'Timestamp: (.+?) UTC', block)
dst = re.search(r'Dst IP: (.+)', block)
ja3 = re.search(r'TLS JA3 Hash: (.+)', block)
frag = re.search(r'Payload Fragment: (.+)', block)
if not (ts and dst and ja3 and frag):
continue
frag = frag.group(1).strip()
if frag == '-':
continue
rows.append((
datetime.strptime(ts.group(1), '%Y-%m-%d %H:%M:%S'),
dst.group(1).strip(),
ja3.group(1).strip(),
frag,
))
rows.sort()
print('_'.join(fragment for _, _, _, fragment in rows))
PY
Results:
- There are 41 non-empty payload fragments.
- All 41 belong to the same destination IP and JA3 cluster, confirming they are the intended sequence.
- Sorting those fragments by timestamp yields the final ordered payload list.
Artifacts Produced
artifacts/ordered_payloads.txt- ordered underscore-separated fragment sequence.
Flag
DawgCTF{HBRPO_IG8F1_CBFNO_6B9M8_0O2RA_K1VRJ_NVGFY_GWWQC_38HYF_9SXME_COSFO_GYR3X_KXWNR_EK8PK_3YR9O_UDOCU_ZRENU_N5Z3J_QIP98_Q1ZXO_I65FD_HJK1E_YY37Q_9AH8R_VHS1K_3AQ6L_6GT6M_JXK87_AU5BH_XTPDP_FF5E8_II49K_Q71N8_MTZX2_72HPO_EVB9O_OAEDO_ECVE6_PR5N8_I4P40_MGG1W1}