PICOCTF 2019 • FORENSICS • LSB STEGANOGRAPHY

What Lies Within: LSB Image Steganography Deconstruction

By Abdo•Aug 31, 2026
What Lies Within Analysis
Official Challenge Prompt

“There's something in the building. Can you retrieve the flag?”

● Category: Steganography / LSB Carving● Points: 150 PTS● Flag Format: picoCTF{...}
Provided File (Download & Practice)Download buildings.pngSize: 625 KB • PNG ImageEncoding: RGB 8-bit/channel
Dissector: Aperi'Solve / zsteg / PIL

Steganography Principle: Least Significant Bit (LSB) Modulation

In 24-bit RGB images, each color channel uses an 8-bit integer (0-255). Modifying the least significant bit (bit 0) alters pixel intensity by at most 1 unit, which is imperceptible to human vision and undetectable on standard displays. By packing consecutive ASCII message bits across the LSBs of sequential color channels (RGB planar order), data is hidden without creating visible visual artifacts.

1. The 5-Step Image Forensics Methodology

Whenever investigating an image in a CTF or incident response investigation, follow this ordered testing pipeline:

[Image File: buildings.png]
     │
     ├── Step 1: Magic Header Check (Verify 89 50 4E 47 ...) ─────────> VALID
     ├── Step 2: Metadata Inspection (ExifTool author/comments) ───────> CLEAN
     ├── Step 3: Plaintext Strings (Check appended EOF strings) ───────> NONE
     ├── Step 4: Signature Carving (Binwalk / Foremost for ZIPs) ──────> NONE
     └── Step 5: LSB Steganography (zsteg / StegSolve / PIL) ─────────> TARGET IDENTIFIED
METHOD A: MANUAL & GUI STEGANOGRAPHY ANALYSIS

2. Inspecting Bit-Planes (Aperi'Solve, StegSolve, zsteg)

How to manually extract the secret payload using specialized stego utilities.

Visual LSB Extraction: StegoToolkit (zsteg Online)Zero-Install Browser Scanner • 65 Combinations Tested

If you don't have Ruby and the native zsteg gem installed on your host machine, you can drop buildings.png directly into StegoToolkit / zsteg Online. Within 120ms, it automatically iterates through all bitplanes and highlights the cleartext flag:

StegoToolkit zsteg Online scan results detecting flag in buildings.png
SCAN VERDICT:CTF flag detected (80% confidence)
picoCTF{h1d1ng_1n_th3_b1t5}
1. Aperi'Solve (Web Platform)GUI Online

1. Navigate to aperisolve.com.
2. Upload buildings.png.
3. Scroll down to the zsteg Analysis section.
4. Notice the detected cleartext string:

b1,rgb,lsb,xy .. text: "picoCTF{h1d1ng_1n_th3_b1t5}"
2. zsteg (CLI Tool)Terminal

Run zsteg to test all permutation combinations (RGB/BGR, MSB/LSB, 1-bit to 8-bit):

$ zsteg buildings.png
b1,rgb,lsb,xy .. text: "picoCTF{h1d1ng_1n_th3_b1t5}"
Decoding the parameter `b1,rgb,lsb,xy`:
b11 bit per color channel
rgbOrder: Red → Green → Blue
lsbLeast Significant Bit (bit 0)
xyLeft-to-right, row-by-row

Step-by-Step Bit Assembly (How the first 4 characters are born):

Character8 Extracted Bits (R, G, B channels)Binary to DecimalASCII Letter
Byte 00 1 1 1 0 0 0 0112'p'
Byte 10 1 1 0 1 0 0 1105'i'
Byte 20 1 1 0 0 0 1 199'c'
Byte 30 1 1 0 1 1 1 1111'o'
METHOD B: CUSTOM PYTHON SOLVER & ONELINER

3. Pure Python LSB Bit Decoder (`solve.py`)

Understanding the math behind LSB lets you write custom extractors with zero external stego tools using Python and the standard PIL (Pillow) library:

from PIL import Image

# 1. Load image and raw pixel raster data
img = Image.open('buildings.png')
pixels = img.load()
width, height = img.size

# 2. Extract the Least Significant Bit (LSB) from R, G, and B channels
bits = []
for y in range(height):
    for x in range(width):
        r, g, b = pixels[x, y][:3]
        bits.append(r & 1)  # Red channel LSB (0 or 1)
        bits.append(g & 1)  # Green channel LSB
        bits.append(b & 1)  # Blue channel LSB

# 3. Assemble consecutive 8 bits into 1 ASCII byte
byte_list = []
for i in range(0, len(bits), 8):
    byte_bits = bits[i:i+8]
    if len(byte_bits) == 8:
        val = 0
        for b in byte_bits:
            val = (val << 1) | b
        byte_list.append(val)

# 4. Decode as string and locate picoCTF flag
extracted_text = bytes(byte_list).decode('latin1', errors='ignore')

if "picoCTF{" in extracted_text:
    start_idx = extracted_text.index("picoCTF{")
    end_idx = extracted_text.index("}", start_idx) + 1
    print("[+] Extracted Flag:", extracted_text[start_idx:end_idx])
Terminal One-Liner (PowerShell / Bash):
python -c "from PIL import Image; img=Image.open('buildings.png'); px=img.load(); w,h=img.size; bits=[c&1 for y in range(h) for x in range(w) for c in px[x,y][:3]]; chars=[chr(int(''.join(map(str,bits[i:i+8])),2)) for i in range(0,len(bits),8)]; txt=''.join(chars); print(txt[txt.find('picoCTF{'):txt.find('}',txt.find('picoCTF{'))+1])"

4. Recovered Flag & Verification

Extracted Flag Payload:

picoCTF{h1d1ng_1n_th3_b1t5}

(Literal meaning: “hiding in the bits” — a direct reference to LSB stego encoding).

5. Steganography Tool Reference Matrix

ToolPlatformBest Use Case
Aperi'SolveWeb BrowserAutomated all-in-one suite running zsteg, steghide, exiftool, and binwalk simultaneously.
zstegRuby CLIGold-standard command-line tool for detecting LSB encoding in PNG and BMP formats.
StegSolveJava DesktopVisual plane-by-plane inspection (Red 0, Green 0, Blue 0, Inverted bitplanes).

6. The Complete Investigation Path & Mental Roadmap

Here is the step-by-step mental roadmap followed to systematically uncover the payload:

STEP 1
Image Triage & Metadata Inspection

Downloaded buildings.png. Ran exiftool and strings to check for easy plain text comments or appended trailers. Results returned clean.

STEP 2
Embedded File Carving

Executed binwalk -e buildings.png to check if another archive or executable was concatenated inside the file. No hidden archives were found.

STEP 3
Bitplane Stego Detection with zsteg / Aperi'Solve

Uploaded image to Aperi'Solve and ran zsteg buildings.png. The scanner instantly identified ASCII flag text hiding on the 1-bit RGB LSB layer (b1,rgb,lsb,xy).

STEP 4
Algorithmic Verification via Python PIL

Wrote a standalone PIL bitmask extractor script to independently verify the bit extraction math without relying on black-box tools.

STEP 5
Flag Capture

Recovered the secret flag: picoCTF{h1d1ng_1n_th3_b1t5}.