Отформатированный код (Formatted code)
Отформатированный код (Formatted code)
Platform: bug-makers | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-29 | Status: Solved Techniques: decoy_source_elimination, space_tab_binary_decoding, trailing_whitespace_extraction
Summary
Task: a single Python file whose title/description stress indentation and whitespace; visible source is a decoy flag-format checker. Solution: each line carries 8 trailing space/tab characters encoding 8 bits (space=0, tab=1); decode bytes to recover the flag, after splitting on CRLF to avoid the trailing-\r pitfall.
Отформатированный код (Formatted code) — bug-makers
Description
При первом знакомстве питон у меня вызывал отвращение из-за необходимости строго соблюдать все отступы в коде, но сейчас я отношусь к этому более спокойно.
English translation: "When I first met Python it disgusted me because of the need to strictly follow all indentation in the code, but now I feel more relaxed about it."
The challenge provides a single Python file check_your_flag.py (3032 bytes, 69 lines). The goal is to recover a BugCTF{...} flag.
Analysis
Semantic clues. The title "Formatted code" plus a description that explicitly dwells on Python indentation and whitespace is a strong pointer to whitespace steganography — data hidden in trailing spaces/tabs at the ends of lines, which are invisible in any normal editor.
The decoy. The visible Python source is a fully working but misleading "flag-format checker":
check_pattern()validates whether an input string looks likeFlag{...}(case-insensitiveFLAG{prefix, even indices not digits, odd indices alphabetic, etc.).main()is a small REPL loop calling that validator.
This logic contains no flag and produces nothing useful — it exists purely to distract from the real payload. Reversing the validator is a dead end.
The real payload. Two key observations about the raw bytes:
- The file uses CRLF (
\r\n) line endings. - Every line has a run of trailing whitespace (spaces and tabs) after the visible code.
Counting the trailing run per line shows exactly 8 whitespace characters per line → 8 bits per line → one byte per line. Mapping space = 0, tab = 1 and concatenating the bits yields a clean ASCII byte stream containing the flag. The inverse mapping (space = 1, tab = 0) produces garbage, confirming the orientation.
CRLF pitfall. If you split the file on \n, each line keeps a trailing \r, which is neither a space nor a tab and silently breaks trailing-whitespace detection (the \r becomes the last char, so the real tail is never read). Split on \r\n (or strip \r) first.
Solution
- Recognize the whitespace-stego hint from the title/description.
- Read the file in binary mode and split on
\r\n. - For each line, walk backwards collecting the run of trailing
0x20/0x09bytes. - Map
space → 0,tab → 1, concatenate into a bit string. - Group into 8-bit bytes and decode to ASCII.
python read-only • copy allowed#!/usr/bin/env python3 # Extract whitespace-stego payload from check_your_flag.py raw = open('check_your_flag.py', 'rb').read() lines = raw.split(b'\r\n') # CRLF split avoids the trailing \r pitfall bits = '' for l in lines: j = len(l) while j > 0 and l[j-1:j] in (b' ', b'\t'): # collect trailing space/tab run j -= 1 tail = l[j:] for c in tail: bits += '0' if c == 32 else '1' # space=0, tab=1 out = ''.join(chr(int(bits[i:i+8], 2)) for i in range(0, len(bits) - 7, 8)) print(out) # -> ...BugCTF{REDACTED}
A few leading bytes are incidental noise from the early structural lines, but the flag portion decodes cleanly.
Canonical tooling. This is exactly the class of payload that stegsnow produces. The equivalent one-liner:
bash read-only • copy allowedstegsnow -C check_your_flag.py
would typically dump the same hidden message, though manual extraction is trivial here and avoids any guesswork about the bit mapping.