Pixelcat
Pixelcat
Platform: taipanbyte | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-02-14 | Status: Solved Techniques: bit_plane_analysis, lsb_extraction, single_channel_lsb
Summary
Task: PNG image of a cat, find hidden flag. Solution: LSB steganography extraction from Red channel only (single-channel LSB), standard RGB extraction fails because G/B bits dilute the data.
Pixelcat — TaipanByte CTF
Description
meow
Files: pixelcat.zip -> meow.png (PNG 720x720, RGB)
Image of a cute cat with a rubber duck on its head.
Analysis
Initial Reconnaissance
bash read-only • copy allowed$ exiftool meow.png # Standard metadata, sRGB ICC profile, nothing suspicious $ strings meow.png | grep -i "TB{" # Nothing found $ xxd meow.png | tail # No data after IEND chunk $ binwalk meow.png # No embedded files
Standard checks (metadata, strings, appended data, embedded files) yielded nothing.
Bit Plane Analysis
Analyzed all 8 bit planes for each of the 3 channels (R, G, B):
- Blue channel bit 7: anomalous ratio 0.3610 (expected ~0.5), but this is just the image structure itself
- LSB (bit 0) in all channels: distribution close to 0.5 — typical sign of LSB steganography (data looks like random noise)
Key Observation
Uniform LSB distribution (~0.5) in all channels is a classic indicator that data has been written to the least significant bits. However, the flag was only in the Red channel.
Solution
Approach
Classic LSB steganography, but with a nuance: data is hidden only in one channel (Red), not in all three (RGB). This is important — when extracting from all channels simultaneously, the flag is unreadable because bits from G and B channels "dilute" the useful data.
Algorithm
- Read all image pixels row by row (top-left -> bottom-right)
- Extract LSB (bit 0) only from Red channel
- Assemble bits into bytes (MSB-first, 8 bits per byte)
- Search for printable ASCII strings 10+ characters long
- Find the flag by pattern
TB{...}
Solution Code
python read-only • copy allowed#!/usr/bin/env python3 """ LSB Steganography Extractor — Single Channel (Red) Extracts hidden data from LSB of Red channel pixels only. """ from PIL import Image import numpy as np import re def extract_red_lsb(image_path, flag_pattern=r'TB\{[^}]+\}'): """Extract LSB data from Red channel and search for flag.""" img = Image.open(image_path) arr = np.array(img) # Extract LSB from Red channel only (index 0) bits = [] for y in range(arr.shape[0]): for x in range(arr.shape[1]): bits.append(arr[y, x, 0] & 1) # Convert bits to bytes (MSB-first) data = bytearray() for i in range(0, len(bits) - 7, 8): byte = 0 for j in range(8): byte = (byte << 1) | bits[i + j] data.append(byte) # Search for flag text = data.decode('latin-1') matches = re.findall(flag_pattern, text) if matches: return matches[0] # Fallback: find any printable strings 10+ chars printable = re.findall(r'[\x20-\x7e]{10,}', text) return printable[:5] if printable else None if __name__ == "__main__": flag = extract_red_lsb('meow.png') print(f"Found flag: {flag}")
Execution
bash read-only • copy allowed$ python3 solve.py Found flag: TB{REDACTED}
Why Standard RGB LSB Doesn't Work
python read-only • copy allowed# Standard approach (all 3 channels) does NOT find the flag: for pixel in pixels: for channel in pixel[:3]: # R, G, B bits.append(channel & 1) # Because bits from G and B channels are inserted between R channel bits, # destroying the byte sequence of the flag. # Need to extract ONLY Red channel.
Alternative Approaches
bash read-only • copy allowed# zsteg — automatic analysis, checks different channels zsteg meow.png # stegsolve — GUI, allows switching bit planes java -jar stegsolve.jar # Quick check of all channels separately: for ch in 0 1 2: python3 -c " from PIL import Image; import numpy as np, re arr = np.array(Image.open('meow.png')) bits = (arr[:,:,$ch] & 1).flatten() data = bytearray(int(''.join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits)-7, 8)) m = re.findall(rb'TB\{[^}]+\}', data) if m: print(f'Channel $ch: {m[0]}') " done
Notes
- When standard LSB (all channels) doesn't work — always check each channel separately
- Red channel is the most common choice for single-channel LSB stego
- PNG is required for LSB (JPEG destroys least significant bits during compression)
- LSB distribution ~0.5 is a strong indicator of hidden data
- For quick checks use
zsteg— it automatically checks all combinations of channels and bits