Description
Most-significant-bit steganography hides data in the high bit of each pixel channel. Use a Python MSB steganography script or Stegsolve to extract the hidden text, then grep for the flag.
Install Stegsolve (or an equivalent tool) and open the provided PNG.
Use Analyse → Data Extract, set bit order to MSB First, and enable Red 7, Green 7, Blue 7. Scroll to the top of the extracted text.
# Option 1: Python MSB extraction scriptpip3 install Pillow# Option 2: Stegsolvewget http://www.caesum.com/handbook/Stegsolve.jar -O stegsolve.jarjava -jar stegsolve.jarSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Extract MSB data
ObservationThe title names the bit plane outright. Extract bit 7 from each pixel channel, not the bit 0 that standard steganography tools reach for.Use a Python MSB steganography script to extract bit 7 from each pixel channel. The extracted bytes concatenated form the hidden text. Alternatively, use Stegsolve: toggle Red 7, Green 7, Blue 7 in the data extractor and save the output.pythonpython3 - <<'PY' from PIL import Image img = Image.open("Ninja-and-Prince-Genji-Ukiyoe-Utagawa-Kunisada.flag.png").convert("RGB") pixels = list(img.getdata()) bits = [] for pixel in pixels: for channel in pixel[:3]: # R, G, B bits.append((channel >> 7) & 1) # MSB # Group bits into bytes out = bytearray() for i in range(0, len(bits) - 7, 8): byte = 0 for b in bits[i:i+8]: byte = (byte << 1) | b out.append(byte) with open("msb_output.bin", "wb") as f: f.write(out) print("Written msb_output.bin") PYbashstrings msb_output.bin | grep picoExpected output
picoCTF{15_y0ur_que57...d55bee}What didn't work first
Tried: Using steghide or zsteg instead of a MSB-aware script, since the file is a PNG with a hidden message.
steghide handles password-based LSB embedding in JPEG and BMP, and reports nothing extractable on this PNG. zsteg checks the lowest bit planes by default and finds nothing, because the flag lives in bit 7. Neither offers arbitrary bit-plane extraction, so use the Python script, or Stegsolve with the top plane of each channel selected.
Tried: Extracting bit 0 (LSB) instead of bit 7 (MSB) by changing '>> 7' to '>> 0' or '& 1' in the Python script.
LSB extraction produces a completely different bit stream, the low-order noise of the image, and the output is binary garbage with no flag in it. The title names bit 7 as the target, so shift each channel right by seven and mask to isolate its most significant bit.
Learn more
In digital images each pixel's color is encoded as a set of channel values (Red, Green, Blue) typically stored as 8-bit integers (0 to 255). Each byte has 8 bit planes: bit 0 is the least significant bit (LSB) and bit 7 is the most significant bit (MSB). Changing bit 7 shifts a channel value by 128, a very visible change. Changing bit 0 shifts it by 1, imperceptible to the human eye.
Classic LSB steganography hides data in bit 0, where changes are invisible. This challenge uses MSB steganography(bit 7) instead. Because the image was specifically chosen to have "natural" high-bit patterns (or was specifically crafted), the flag hidden in the MSB is not visually obvious. Stegsolve's data extractor reads the selected bit from every pixel in row-major order and concatenates them into a byte stream, which surfaces the hidden ASCII text.
Stegsolve is a Java tool that provides bit-plane viewers, color filters, and frame analyzers. It is invaluable for CTF image steganography because it visualizes every bit plane at a glance: a pattern of text in an otherwise noisy bit plane is a dead giveaway that data is hidden there. The full bit-plane workflow is covered in the CTF steganography and steganography tools guides.
Step 2Search the dump
ObservationThe extraction script writes raw binary to msb_output.bin, and the flag will sit surrounded by non-printable bytes. Filter with strings before grepping for the prefix.Stegsolve's data extractor saves the raw bytes (the default save dialog dumps to a file you choose; many people just save it as text in the same directory). Run strings on the saved file and grep for pico. Remove stray spaces from the recovered flag if MSB alignment introduced any.bashstrings text | grep picoExpected output
picoCTF{15_y0ur_que57...d55bee}What didn't work first
Tried: Running 'strings text | grep pico' but using the original PNG file rather than the MSB-extracted output file.
Running strings on the original PNG scans the raw bytes: metadata, compressed pixel data, ancillary chunks. The flag is not literal ASCII anywhere in there, being encoded bit by bit across pixel channels. Only after extraction and byte reconstruction does it become printable text strings can find.
Tried: Grepping the extracted file directly without strings, using 'grep pico msb_output.bin' or opening it in a text editor.
grep sees the NUL bytes, decides the file is binary, and suppresses the matching line entirely (at most it prints 'binary file matches'), so the flag never reaches your terminal. Passing -a forces it to treat the file as text. The extracted stream is thick with non-printable bytes around the flag text. strings filters for contiguous printable runs first, which surfaces the characters cleanly whatever the surrounding noise.
Learn more
After extraction, the raw byte stream may contain the flag interleaved with garbage bytes, or the flag may be contiguous.
stringsfilters for sequences of printable ASCII characters of a minimum length (default 4), which naturally isolates human-readable content likepicoCTF{...}from surrounding binary data.The
grep picopipe then narrows the output to only lines containing the flag prefix. This two-step pipeline -strings | grep pattern- is a general-purpose technique applicable to any binary file: ELF binaries, firmware dumps, memory captures, or steg output. It is often the fastest first step in any binary analysis task.About those spaces: MSB extraction reads one bit per channel per pixel, then groups the resulting bit stream into 8-bit bytes. If the hidden message is shorter than the image (or padded with zero-bytes), runs of zero bits decode to NULs (0x00) which print as nothing, and runs of
0x20bytes decode as ASCII space. Strip extra whitespace before submitting.
Interactive tools
- StegallDrop any file and Stegall runs every applicable steg technique in parallel: LSB sweeps, bit planes, spectrograms, polyglot carving, metadata, whitespace decode, and a 6-layer base/ROT/XOR/zlib cascade. Recursively unpacks results and surfaces flag matches.
- Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
Flag
Reveal flag
picoCTF{15_y0ur_que57...d55bee}
Only the MSB bits carry useful data, so LSB analysis will pass but yield nothing.