HackBlue

Tools · CTF categories for beginners · 06 / 18

Steganography basics for CTFs: LSB data, steghide, zsteg, and spectrograms

Understand how data hides in images and audio, check the obvious places first, use steghide, zsteg, and stegseek on practice files, and view audio spectrograms.

10 min read · practice only with authorization

Where data hides

Simple hiding places include metadata, appended data, and text in image comments, which the triage routine finds. Least significant bit (LSB) steganography changes the lowest bit of pixel color values, which is invisible to the eye. Tools like steghide embed encrypted data in JPEG and BMP files with a passphrase. In audio, messages are sometimes drawn into the spectrogram, visible only when you plot frequency against time.

Tools

zsteg checks PNG and BMP files for LSB data in many bit and channel combinations. steghide extracts data embedded with a passphrase. stegseek tries a wordlist against steghide files very quickly, which is appropriate only for challenge files. Audacity or Sonic Visualiser show spectrograms. StegSolve or Aperi’Solve let you view individual bit planes.

Snippet
zsteg -a image.png | head -30
steghide info cover.jpg
steghide extract -sf cover.jpg -p 'passphrase-from-hint'
stegseek cover.jpg /usr/share/wordlists/rockyou.txt   # practice files only
sox audio.wav -n spectrogram -o spec.png

Lab: hide and find

Create your own practice files: embed a short text in a JPEG with steghide and a passphrase, and write a PNG with a message in the least significant bits using a short Python script with Pillow. Then extract both. Finally, open the PNG in a bit-plane viewer and see the message’s noise pattern in plane 0.

Snippet
steghide embed -cf cover.jpg -ef secret.txt -p lab-pass
steghide extract -sf cover.jpg -p lab-pass -xf out.txt

python3 - <<'EOF'
from PIL import Image
msg = 'flag{lsb_practice}'.encode() + b'\x00'
bits = ''.join(f'{b:08b}' for b in msg)
img = Image.open('plain.png').convert('RGB'); px = img.load()
w, h = img.size
for i, bit in enumerate(bits):
    x, y = i % w, i // w
    r, g, b = px[x, y]; px[x, y] = ((r & ~1) | int(bit), g, b)
img.save('stego.png')
EOF
zsteg stego.png | grep -i flag

A sensible approach

Start with triage, then zsteg for PNG or BMP, steghide info for JPEG, and a spectrogram for audio. Read the challenge text carefully: passphrases and hints are often in the title or description. Avoid running random tools endlessly; each one should test a specific hypothesis.

Diagram

Stego hiding places

Check in this order.

  • Metadata and comments

    exiftool finds them.

  • Appended data

    binwalk and xxd find them.

  • LSB in PNG/BMP

    zsteg and bit-plane viewers.

  • steghide in JPEG/BMP

    Needs a passphrase, often hinted.

  • Audio spectrogram

    Plot frequency over time.

Check yourself

1. What does LSB steganography modify?

2. Which tool scans PNG files for LSB-hidden data?

3. A challenge gives a WAV file with a strange hiss. What should you view?