PICOCTF 2019 • FORENSICS • LSB STEGANOGRAPHY

What Lies Within: LSB Image Steganography Deconstruction

By AbdoAug 31, 2026
What Lies Within Analysis
Official Challenge Prompt

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

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

💡 THE INTUITIVE ANALOGY (How LSB Works)

Every digital color is represented by numbers from 0 to 255 across Red, Green, and Blue. In binary, 254 is 11111110 and 255 is 11111111. The human eye cannot tell the difference between shade 254 and shade 255. By flipping only the very last bit (the Least Significant Bit) of each pixel, an attacker can secretly store millions of secret binary 1s and 0s directly inside the image without modifying the visible picture!

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.

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}.

Cyber Amber
#f59e0b
PresetsClick to lock