awk...wardddd ✂️
awk...wardddd ✂️
Platform: bluehensctf | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-04-21 | Status: Solved Techniques: base64_decoding, part_reassembly, record_filtering
Summary
Task: ZIP archive containing thousands of small record files with shuffled fields and decoy metadata. Solution: Filter the retained active sys_*.rec records, sort by part, and base64-decode each data fragment to reconstruct the flag.
awk...wardddd ✂️ — BlueHens CTF 2026
Description
Provided artifact:
s0rry_in_4dv4nc3.zip
The archive contains many small record files. The goal is to identify the meaningful subset and recover the hidden flag.
Analysis
After extraction, the archive contains 10018 files spread across archive/, logs/, reports/, tmp/, and users/.
Almost all records are 7-line key=value files with these fields:
timestampprofileuidstatepartdatanote
Another 1483 files also include:
text read-only • copy allowedcomment=VURDVEZ7ZmFrZV9mbGFnfQ==
That base64-decodes to a fake flag decoy, so those records are noise.
The useful files are the only consistent outliers: 7 files named sys_*.rec with:
profile=deltastate=activenote=retained
Their field order is intentionally shuffled, but the part values cover 01 through 07, which strongly suggests ordered fragments.
Solution
- Unzip the archive and scan all extracted records.
- Parse each file as unordered
key=valuedata. - Ignore the fake-flag
commentdecoys. - Keep only records where
profile=delta,state=active, andnote=retained. - Sort the remaining 7 records by
part. - Base64-decode each
datavalue and concatenate the decoded fragments.
Recovered fragments:
text read-only • copy allowed01 VURDVEZ7 -> UDCTF{ 02 dzNsbF83 -> w3ll_7 03 aDQ3X3c0 -> h47_w4 04 NW4nN183 -> 5n'7_7 05 MF9oNHJk -> 0_h4rd 06 X3c0NV8x -> _w45_1 07 Nz99 -> 7?}
Final flag:
text read-only • copy allowedUDCTF{REDACTED}
python read-only • copy allowed#!/usr/bin/env python3 from pathlib import Path import base64 import sys def parse_record(path: Path): fields = {} for line in path.read_text(errors="ignore").splitlines(): if "=" in line: k, v = line.split("=", 1) fields[k] = v return fields def main(root: str): records = [] for path in Path(root).rglob("*.rec"): fields = parse_record(path) if ( path.name.startswith("sys_") and fields.get("profile") == "delta" and fields.get("state") == "active" and fields.get("note") == "retained" ): records.append((fields.get("part", ""), fields.get("data", ""), path.name)) records.sort() for part, data, name in records: frag = base64.b64decode(data).decode() print(f"{part} {data} -> {frag} ({name})") flag = "".join(base64.b64decode(data).decode() for part, data, _ in records) print(f"\nFlag: {flag}") if __name__ == "__main__": if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} <extracted_archive_dir>") raise SystemExit(1) main(sys.argv[1])