ctf-stego
Use when solving steganography CTF challenges — hidden data in images (PNG/JPG/BMP), audio (WAV/MP3), video, or text. Triggers on "ctf stego", "steganography", "hidden in image", "audio stego", "lsb".
SKILL.md.claude/skills/ctf-stego/SKILL.md
GitHubCTF stego methodology
0. CRITICAL — never Read an unvalidated image
Per CLAUDE.md: reading a corrupt image poisons the conversation. Validate first:
run_tool("file", "/path/to/image")
run_tool("identify", "/path/to/image") # ImageMagick
# or run_script:
# from PIL import Image; img = Image.open(path); print(img.size, img.mode)
Only Read the image after both checks pass.
1. Triage every input
file <file>
xxd <file> | head -30
exiftool <file> # metadata — flag often hides here
strings <file> | grep -i "ctf\|flag\|key\|pass" | head
binwalk <file> # multi-file polyglots
Always check metadata first. ~30% of intro stego is just exiftool.
2. Image (PNG / JPG / BMP / GIF)
| Technique | Tool / approach |
|---|---|
| LSB in pixels | zsteg (PNG/BMP), stegsolve |
| EOF data after IEND/EOI | binwalk -e, manual hex |
| JPG specific | steghide extract -sf <file> (often with empty pass), stegseek for brute |
| PNG color planes | stegsolve (visual layer toggle) |
| LSB matching, custom | zsteg -a, then write custom Python with PIL |
| Polyglot (file with valid headers for multiple formats) | binwalk, foremost |
| File appended after IEND chunk (PNG) | pngcheck -v, manual carve |
| Modified/extra chunks | pngcheck -v, pngcsum |
| Width/height tampering (PNG) | edit IHDR width/height, recalc CRC — tweakpng style |
# zsteg covers most LSB cases for PNG/BMP
zsteg -a image.png
# steghide brute (jpg/wav/bmp)
stegseek image.jpg rockyou.txt
# Multi-tool sweep
stegsolve image.png # GUI, manual layer toggle
3. Audio (WAV / MP3 / FLAC / OGG)
| Technique | Tool |
|---|---|
| LSB in samples | wavsteg, custom python |
| Steghide payload | steghide, stegseek |
| Spectrogram (visual hidden in freq domain) | audacity view spectrogram, sonic-visualiser |
| DTMF tones | multimon-ng -a DTMF, manual tone analysis |
| Morse | listen by ear, then morse-decoder or manual |
| SSTV (slow-scan TV in audio) | qsstv, slowrx |
# Spectrogram via sox
sox audio.wav -n spectrogram -o spec.png
# Then validate spec.png before reading (see step 0)
# DTMF
multimon-ng -a DTMF audio.wav
4. Video / GIF
# Extract frames
ffmpeg -i video.mp4 -vf fps=1 frames/frame_%04d.png
# Per-frame stego
for f in frames/*.png; do zsteg -a "$f" 2>/dev/null | grep -i "flag\|ctf"; done
# Audio track
ffmpeg -i video.mp4 -vn audio.wav
# Then audio analysis
5. Text / Unicode
| Technique | Tool |
|---|---|
| Zero-width characters | zwsp-steg, manual unicode inspect |
| Whitespace stego | snow, stegsnow |
| Homoglyph substitution | unicode normalize + diff |
| Base-N nested encodings | ciphey, manual |
| Bacon / null cipher | manual + dcode.fr |
# Show every character including invisibles
python3 -c "import sys; [print(repr(c), hex(ord(c))) for c in open(sys.argv[1]).read()]" file.txt
6. Less common
- PDF:
pdf-parser,peepdf,qpdf --qdf— check streams, annotations, JS, attachments - Office docs:
oletools(olevba,oleid),oledump, unzip the .docx/.xlsx - QR / barcode:
zbarimg,zxing— also try partial QR reconstruction - DNA/protein sequences: ROT/encoding tricks, decode A/C/G/T as base-4
7. Default workflow
exiftool+strings+binwalk -ealways first- If image →
zsteg -a(PNG/BMP) ORstegseek(JPG) - If audio → spectrogram view
- If nothing obvious →
stegsolveGUI for visual analysis - If still nothing → metadata might encode the answer (look at GPS, comment, software field)
8. Don't waste time on
- LSB scripts when
zstegexists - Manually viewing spectrograms in matplotlib when audacity/sonic-visualiser exist
- Reading the image with
Readbefore validation (see step 0)
After solve
Use the writeup-template skill.