← Back to Writeups
CUSTOMEasyForensics

awk...wardddd ✂️

XESXOR9/2/20262 min read
#forensics#custom#easy#base64_decoding#part_reassembly#record_filtering

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:

  • timestamp
  • profile
  • uid
  • state
  • part
  • data
  • note

Another 1483 files also include: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

text
comment=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=delta
  • state=active
  • note=retained

Their field order is intentionally shuffled, but the part values cover 01 through 07, which strongly suggests ordered fragments.

Solution

  1. Unzip the archive and scan all extracted records.
  2. Parse each file as unordered key=value data.
  3. Ignore the fake-flag comment decoys.
  4. Keep only records where profile=delta, state=active, and note=retained.
  5. Sort the remaining 7 records by part.
  6. Base64-decode each data value and concatenate the decoded fragments. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Recovered fragments:

text
01 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
UDCTF{REDACTED}
python
#!/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])

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍