Skip to main content

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 Fragment fields 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.45 sharing JA3 d2b4c6a8f0e1d3c5b7a9f2e4d6c8b0a1.

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}