Steganography CTF: binwalk, stegide and zsteg part 2

Depov

Moderator
Staff member
MODERATOR
ULTIMATE
SUPREME
PREMIUM
MEMBER
Joined
Feb 18, 2025
Messages
627
Reaction score
1,219
Deposit
0$
Checking and Extracting

The first step is steghide info target.jpg. The utility will ask for a password: press Enter for an empty password. An amazing number of lightweight tasks embed data without protection – the authors of the Tasks, apparently, expect that the participants will simply not reach steghide. If stegide shows the name of the attached file, its size and encryption algorithm (usually Rijndael-128, CBC) - the data is accurate.

Extraction: steghide extract -sf target.jpg. Password can be hidden in file metadata (check output exiftool), in the text of the job description, in the file name or in the output strings. Sometimes the password is coded in base64 directly in the JPEG commentary – as in the mentioned case with picoCTF.

Trap for beginners: messages with the wrong password and in the complete absence of nested data look the same - could not extract any data with that passphrase!. It is possible to distinguish situations only through steghide info with the right password that creates a vicious circle. Practical approach: If the task involves steganography and a JPEG or WAV format file, consider that steghide is used, and look for a password more carefully, rather than switching to another tool.
Brute-force: stegseek instead of stegcracker

When the password is not manually, you need a brute-force. The difference between the tools here is heaven and earth.

StegCracker starts a separate stegide process for each password from the dictionary. On rockyou.txt (14 million records) it takes a watch — every steghide call counts the hashes anew. On CTF, where time is limited, it's simply not allowed.

Stegseek works directly with the stegide library, bypassing recalculations. The same rockyou.txt is processed in seconds. Team: stegseek target.jpg /usr/share/wordlists/rockyou.txt. With a successful selection, stegseek immediately extracts data.

If stegseek has not found a password, a custom password outside of standard dictionaries is used or the data is hidden by another tool.
zsteg and LSB steganography in PNG

zsteg is the main tool for finding hidden information in PNG and BMP images. It analyzes the lower bits (Least Significant Bit) in the color channels and goes through a lot of coding combinations.
How LSB Coding Works

Each PNG pixel stores the values of red, green and blue channels of 8 bits (256 values per channel). In LSB steganography, the last bit of each channel is replaced by a secret message bit. Visually, the picture does not change: the color shift to 1 out of 256 is invisible. But bits are recoverable - just read the junior ranks in the correct order.

The variability of the method creates complexity: the data can be in one channel (only R), in all three (RGB), in reverse order (BGR), on rows (xy) or by columns (yx), in the first bit or in the second. There are many combinations, manually going through is madness. For this purpose there is zsteg.
zsteg in practice

Team zsteg -a file.png starts a complete overkill: channels (R, G, B, A), orders (RGB, BGR, GBR and others), bypass directions (xy, yx) and bit planes (b1, b2, b3...). The output is voluminous – look for lines with meaningful text, ASCII patterns, or file signatures (PK for ZIP, \x89PNG for the image).

To extract a specific payload: zsteg -E b1,rgb,lsb,xy file.png > output.bin, where b1 – the first bit, rgb – order of channels, lsb - the younger beat, xy - a line bypass. The parameters are selected according to the results zsteg -a: the tool itself indicates in which combination the data was found.

The fundamental difference from stegide: zsteg does not require a password. If the data is encoded in LSB — it is extracted directly, without a key. stegide encrypts payload (by default Rijndael-128), and zsteg works with open data. These are two different approaches to steganography, and to confuse them is to waste time.

Installation: gem install zsteg (Requires Ruby). On Kali Linux is usually pre-installed.
stegsolve: manual visual analysis of layers

When zsteg found nothing, but the suspicion of steganography in the pictures remains - stegsolve allows you to view the image on individual color planes. Java application, run through java -jar stegsolve.jar.

Three modes that are actually applied to CTFs:

Switching layers – arrows go overboard Red plane 0, Green plane 1, Blue plane 7, etc. Hidden text or QR code is sometimes visible only on a specific channel plane. You poke with arrows until something meaningful shows up.

Data Extract – select specific bits of specific channels and read data. If zsteg showed the result in b1,rgb,lsb, Data Extract allows visual confirmation of the find.

Image Combiner - overlays two images through operations XOR, ADD, SUB. If the task is given the original and the modified file, XOR will show the pixels in which the data is hidden. This regime is often forgotten, but in vain.
Audio file steganography: spectrograms and LSB

Audio steganography in CTF is divided into two fundamentally different approaches: data is encoded in samples (LSB) or hidden as a visual pattern on a spectrogram.
Spectrograms in Sonic Visualiser and Audacity

Open the audio file in Sonic Visualiser, add a layer of spectrogram (Layer → Add Spectrogram). If in the frequency range of 8-20 kHz you can see clear lines that form letters, text or QR code - this is a spectrogram steganography. Sonic Visualiser gives a fine control over the visualization parameters: the size of the FFT window, the color map, the scale of the frequencies. The larger the FFT window, the better the resolution in frequency – 2048 or 4096 is usually suitable for text in a spectrogram.

In Audacity, a similar result: open the file, switch the track to Spectrogram mode through the drop-down menu. Increase the upper limit of the frequencies to the maximum in the spectrogram settings.

Morse code is another classic technique. On the oscillogram, it looks like an alternation of silence and tone with characteristic long and short pulses. Decryption – manually or through an online decoder. It sounds simple, but in practice, distinguishing the points from the dash on the noisy signal is not trivial.
LSB in WAV files

For WAV with hidden data in the younger bits of samples, stegide (if payload is password-protected) or WavSteg (password-free extraction) are used: python3 WavSteg.py -r -s sound.wav -o output.txt.

Audio file verification procedure: file audio.wav (real format?) → strings audio.wav | grep -i flag (open text?) → binwalk audio.wav (injected files?) → Sonic Visualiser for spectrogram → steghide info for WAV → WavSteg for LSB.
Solutions tree: forensics CTF algorithm

The main problem of CTF steganography is not the lack of tools, but the choice of the right one. The table below is a reference that should be kept open at every competition:
Format The first instrument Alternative What to look at
JPEG stegide info stegseek (brute-force) DCT payload, password is required
PNG zsteg -a stegsolve, binwalk LSB in RGB/RGBA channels
BMP zsteg or steghide stegsolve Both instruments are applicable
WAV steghide, Sonic Visualiser WavSteg, Audacity LSB samples or spectrogram
GIF Stegsolve (Frame browser) ImageMagick convert Data in separate frames
MP3/FLAC strings, binwalk Sonic Visualiser Metadata, attachments, spectrogram
Anybody file, strings, exiftool binwalk -e Always start with intelligence

Full workflow for each forensics CTF assignment with steganography:

file target # 1. реальный формат
strings target | grep -iE "flag|ctf|key|pass" # 2. открытый текст
exiftool target # 3. метаданные
binwalk target # 4. вложенные файлы
# JPEG/BMP/WAV:
steghide info target # 5. пустой пароль (Enter)
# PNG/BMP:
zsteg -a target # 6. LSB-анализ
# аудио без результата:
# Sonic Visualiser → спектрограмма # 7. визуальный анализ
# steghide нашёл данные, пароль неизвестен:
stegseek target /usr/share/wordlists/rockyou.txt # 8. brute-force

This algorithm covers the vast majority of easy and medium-level stego tasks. On complex tacks are connected hex-analysis (through xxd or hexdump), custom Python scripts and PNG-padding check.
Python for non-standard LSB

When zsteg does not cope with non-standard LSB-coding (atypical order of channels, bits are not in the younger position, custom pixels), the manual script helps:

from PIL import Image

img = Image.open('steg.png')
bits = ''
for y in range(img.height):
for x in range(img.width):
r, g, b = img.getpixel((x, y))[:3]
bits += str(r & 1) + str(g & 1) + str(b & 1)
text = ''.join(chr(int(bits[i:i+8], 2)) for i in range(0, len(bits), 8))
print(text[:500])

The script reads the younger bit of each channel (R, G, B) of each pixel by rows, collects bits in bytes and outputs as text. The order of circumvention (xy → yx), the choice of the channel and the number of the bit (& 1 for LSB, & 2 for the second bat, & 4 for the third) - parameters that are selected for a specific task. Brute-force on these parameters through the script takes less than a minute.
Hidden data beyond PNG borders

A method that is not caught by either zsteg, stegide, or binwalk in standard mode – PNG filling beyond the boundaries of the visible area (post-pixel padding). Principle: PNG image is taken, secret information is added to the lower part (text, another picture, archive), then the height value in the IHDR block decreases in the hex editor. The renderer shows a picture with a lower height — the bottom lines of the pixels are ignored, but the data remains inside the IDAT blocks.

PNG Structure: The file starts with an 8-byte signature (89 50 4E 47 0D 0A 1A 0A), then the IHDR block with width (4 bytes) and height (4 bytes), then IDAT data and the final IEND block. The height is recorded by displacement 0x14–0x17 from the beginning of the file.

You can find padding in several ways. The utility pngcheck -v file.png will report the discrepancy between the declared size and volume of IDAT data. In the hex editor, you can manually increase the height value, recalculate the CRC block IHDR (four bytes immediately after the block data) and see the hidden part of the image. For recalculation of CRC – Python script with module zlib.crc32 or online tools.

This technique is found on the mid-level CTF – especially in tasks where standard tools for CTF forensics give an empty result. If the binwalk is silent, the zsteg is empty, and the file is suspiciously heavy, check the height in the IHDR.
 
Top Bottom