← Back to Writeups
CUSTOMMediumForensics

Слив флагов (Flag Leak)

XESXOR9/2/20263 min read
#forensics#custom#medium#ads_extraction#base64_decoding#dd_carving#wim_analysis#wimlib_imagex#windows

Слив флагов (Flag Leak)

Platform: bug-makers | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Windows | Author: XESXOR | Date: 2025-10-04 | Status: Solved Techniques: ads_extraction, base64_decoding, dd_carving, wim_analysis, wimlib_imagex

Summary

Task: a WIM archive with 1000 decoy base64 flag files, one real flag hidden. Solution: spotted an NTFS Alternate Data Stream in the 7z summary, used wimlib-imagex to locate the named 'hidden' stream on flag_404.txt, carved its 47 bytes with dd, and base64-decoded the flag.

Слив флагов (Flag Leak) — bug-makers

Description

Слив флагов. Это новостной дайджест, и мы начинаем! Хакеры слили флаги Багодельни! Тысячи флагов в одном архиве. Флаги оказались зашифрованы, но хакеры утверждают, что один флаг ТОЧНО реален, и находится среди файлов. Что? Еще не воскресенье? Пардон. В любом случае флаг где то здесь. Покопайтесь.

English summary: A single file flags.wim (232417 bytes) is provided. It contains thousands of "encrypted" flags, but exactly one real flag is hidden among the files. The goal is to dig through the archive and find it. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Analysis

file flags.wim identifies it as a Windows Imaging (WIM) image v1.13 with reparse-point fixup — a Microsoft deployment image format that can preserve full NTFS metadata, including Alternate Data Streams (ADS).

Listing with 7z l flags.wim shows 1000 files flags/flag_000.txt … flags/flag_999.txt, each exactly 45 bytes. Each file holds a base64 string that decodes to 32 hex characters plus 1 trailing random letter (e.g. eee1cc00452673716974e796f7a8fa4c8). Every file has distinct random content — these are 1000 decoys. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The crucial clue is the 7z summary footer:

1000 files, 1 folders
1 alternate streams        <-- 47 bytes
1001 streams

There are 1001 streams for 1000 files — a single NTFS Alternate Data Stream is preserved inside the WIM. 7z reports the existence of the ADS but does NOT tell you which file owns it. That is the entire puzzle: ignore the 1000 random decoys and find the one hidden stream.

Solution

  1. Confirm the format and the ADS clue:

    bash
    file flags.wim
    # Windows imaging (WIM) image v1.13, reparse point fixup
    7z l flags.wim
    # ... 1000 files, 1 folders / 1 alternate streams / 1001 streams

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

  1. 7z won't reveal the ADS owner, so use wimlib (brew install wimlib) which enumerates named data streams with their in-WIM byte offsets:

    bash
    wimlib-imagex dir flags.wim 1 --detailed

    This reveals a named data stream "hidden" attached to /flags/flag_404.txt:

    Named data stream "hidden":
    Hash              = 0x9fc464666c7ac34b432899c3f32af11c53f8626f
    Uncompressed size = 47 bytes
    Offset in WIM     = 18433 bytes
    

    (The filename flag_404.txt is itself a nod — "not found" among the visible flags.) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

  2. Carve the raw 47 bytes directly from the WIM using the reported offset (mounting a WIM and reading an ADS is impractical on macOS/Linux, so dd is the clean path):

    bash
    dd if=flags.wim bs=1 skip=18433 count=47
    # QnVnQ1RGe0gxREQzTl9TVFIzNE1fRjBSX01ZX0ZMNEd9=   (with trailing CRLF)
  3. Base64-decode the stream contents:

    bash
    echo -n "QnVnQ1RGe0gxREQzTl9TVFIzNE1fRjBSX01ZX0ZMNEd9" | base64 -d
    # BugCTF{REDACTED}

One-shot script

bash
#!/usr/bin/env bash
set -e
# 1. Identify the WIM and spot the ADS in the 7z summary
file flags.wim
7z l flags.wim | grep -i "alternate stream"
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# 2. Locate the named data stream and its offset
wimlib-imagex dir flags.wim 1 --detailed | grep -A4 'Named data stream'

# 3. Carve the 47-byte hidden stream at offset 18433 and decode
dd if=flags.wim bs=1 skip=18433 count=47 2>/dev/null | tr -d '\r\n' | base64 -d
echo

Failed Approaches (for other solvers)

  • Treating the 1000 base64 decoys as the puzzle (hex-decoding them, concatenating trailing characters) — all distinct random data, no signal.
  • The WIM content-dedup angle (expecting 999 identical files + 1 different) — did not apply; all 1000 files had distinct hashes. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍