$ file challenge.bin
challenge.bin: Zip archive data, at least v2.0 to extract $ xxd challenge.bin | head -5
00000000: 504b 0304 1400 0000 0800 ... PK..........
$ file challenge.bin
challenge.bin: Zip archive data, at least v2.0 to extract $ xxd challenge.bin | head -5
00000000: 504b 0304 1400 0000 0800 ... PK..........
$ file challenge.bin
challenge.bin: Zip archive data, at least v2.0 to extract $ xxd challenge.bin | head -5
00000000: 504b 0304 1400 0000 0800 ... PK..........
50 4B 03 04
# 1. What is this file?
file challenge.*
xxd challenge.* | head -30 # 2. Anything embedded?
binwalk challenge.*
strings challenge.* | grep -i flag # Example output that changes my approach:
$ strings mystery.dat | grep -i flag
picoCTF{hidden_in_plain_sight_3a9f2}
# Done in 10 seconds. Sometimes it's that simple. # 3. Branch based on file type
# → disk image: fdisk → dd → mount
# → audio: Audacity spectrogram → sox/ffmpeg
# → image: pngcheck → steghide
# → archive: zip2john (check encryption type first)
# → PDF: pdfdumper
# → QR/barcode: zbarimg
# 1. What is this file?
file challenge.*
xxd challenge.* | head -30 # 2. Anything embedded?
binwalk challenge.*
strings challenge.* | grep -i flag # Example output that changes my approach:
$ strings mystery.dat | grep -i flag
picoCTF{hidden_in_plain_sight_3a9f2}
# Done in 10 seconds. Sometimes it's that simple. # 3. Branch based on file type
# → disk image: fdisk → dd → mount
# → audio: Audacity spectrogram → sox/ffmpeg
# → image: pngcheck → steghide
# → archive: zip2john (check encryption type first)
# → PDF: pdfdumper
# → QR/barcode: zbarimg
# 1. What is this file?
file challenge.*
xxd challenge.* | head -30 # 2. Anything embedded?
binwalk challenge.*
strings challenge.* | grep -i flag # Example output that changes my approach:
$ strings mystery.dat | grep -i flag
picoCTF{hidden_in_plain_sight_3a9f2}
# Done in 10 seconds. Sometimes it's that simple. # 3. Branch based on file type
# → disk image: fdisk → dd → mount
# → audio: Audacity spectrogram → sox/ffmpeg
# → image: pngcheck → steghide
# → archive: zip2john (check encryption type first)
# → PDF: pdfdumper
# → QR/barcode: zbarimg - fdisk — read the partition table first. Tells you how many partitions exist and their offsets.
- dd — carve out individual partitions by byte offset for closer inspection.
- mount — only after you know the partition layout. Mounting blindly often fails; fdisk tells you the offset you need for the -o flag. - Audacity — open the file and switch to spectrogram view immediately. If there's a visual message hidden in the frequency domain, you'll see it in seconds. This is the tool I open first for any audio challenge.
- SoX — when I need to script audio analysis or batch-process files. Also useful for speed/pitch manipulation when a challenge hints that audio has been distorted.
- FFmpeg — for video files or when a challenge mixes audio and video. Also my go-to when a file won't open in Audacity due to codec issues — FFmpeg can transcode it first. - pngcheck — run this first on any PNG. It validates chunk integrity and will immediately flag if something is wrong with the file structure. A challenge with a "broken" PNG almost always has an intentionally modified chunk.
- steghide — for JPEG/BMP files that might have data embedded with a passphrase. If the challenge gives you a password hint, steghide is usually involved.
- binwalk — when the image looks clean but is suspiciously large. Scans for embedded files and compressed data appended after the image end. - pdfdumper — PDFs are containers. pdfdumper extracts embedded objects, JavaScript, and hidden streams that you'd never see just opening the file normally.
- zip2john — for password-protected ZIPs. The key thing here is identifying the encryption type first: ZipCrypto is crackable with zip2john + hashcat/john, but AES-256 encryption requires the actual password. I wrote about this distinction in detail in the zip2john article. - zbarimg — the fastest way to decode QR/barcodes from the command line. The Scan Surprise challenge in picoCTF is a straightforward example — see the writeup for how it plays out in practice. - Wrong file type assumption — the extension lies. Always check magic bytes with file and xxd.
- Multiple layers — extracting one file from a ZIP and stopping. There's often another layer inside.
- Mounting without reading partition offsets — mount fails or mounts the wrong partition when you skip fdisk.
- AES-256 ZIP + zip2john — zip2john cannot crack AES-256 encrypted ZIPs. If you're seeing $zip2$* in john output, you need the actual password, not a dictionary attack.
- Spectrogram at wrong scale — if Audacity's spectrogram looks like noise, zoom in on the frequency range 1–4kHz. Flags are sometimes hidden in a narrow band that's invisible at default zoom.