Skip to main content

Milkslap picoCTF 2021 Solution

Investigate a web page image for data hidden within the pixel values using steganographic techniques.

Published: April 2, 2026Updated: August 25, 2026

Description

Milk... Slap... Do the words make sense to you? Download milkslap.png.

Open the challenge URL in a browser to find the embedded image.

bash
# Open the challenge URL and view source / Network tab

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
Companion reading: CTF Steganography Techniques explains the LSB encoding zsteg unpacks, and Steganography Tools lists zsteg / stegsolve / steghide and when to reach for each.
  1. Step 1Discover the embedded image from the page
    Observation
    The description says to download milkslap.png but links to a web page rather than the file. So the PNG is a sub-resource inside the page's markup, and the source or the Network tab holds its real URL.
    Open the page and either view source or open DevTools Network tab. The image URL appears as an <img src="..."> reference (or as a background-image in CSS). Pull it down with wget so you can run tools on the file directly.
    bash
    curl -s <CHALLENGE_URL> | grep -Eo 'src="[^"]+\.png"' | sort -u
    bash
    wget <DISCOVERED_PNG_URL> -O milkslap.png
    bash
    file milkslap.png

    Expected output

    milkslap.png: PNG image data, 1280 x 720, 8-bit/color RGB, non-interlaced
    What didn't work first

    Tried: Navigate directly to the challenge URL and assume the page itself is the downloadable PNG, saving the HTML response as milkslap.png.

    The challenge URL returns an HTML page, not the image binary: file reports an HTML document and zsteg refuses to parse it. The PNG loads as a sub-resource from the page's markup, so grep the HTML for the img src attribute to find the real URL before downloading.

    Tried: Skip the page inspection and guess the PNG URL by appending /milkslap.png to the challenge base URL.

    Without the page source or the DevTools Network tab, the sub-resource path is unknown. Guessing common suffixes usually gives a 404, and even a matching filename fails if the subdirectory differs. Grepping the markup extracts the exact src value the server actually serves.

    Learn more

    Why scan the page first. picoCTF stego challenges often hide the actual image one or two levels into the HTML rather than in a download link. view-source: in the browser address bar, or curl <url> piped through grep, reveals every resource the page loads. CSS background-images and lazy-loaded data-src attributes are common tricks - check both.

  2. Step 2Run zsteg to detect LSB steganography
    Observation
    The image is a plain PNG with no password prompt anywhere. That reads as LSB steganography in the pixel data, and zsteg scans every bit plane and channel ordering automatically.
    Use zsteg on the image to automatically detect and extract data hidden in the least significant bits of the image pixels. The flag is hidden using LSB steganography.
    bash
    zsteg milkslap.png
    bash
    zsteg -a milkslap.png  # exhaustive

    Expected output

    b1,r,lsb,xy         .. text: "picoCTF{imag3_m4n1pul4t10n_sl4p5}"
    What didn't work first

    Tried: Run steghide extract -sf milkslap.png on the image expecting to recover the flag that way.

    steghide supports JPEG, BMP, WAV, and AU carriers only, and rejects a PNG outright as an unsupported format. LSB encoding in a PNG is a different technique anyway: steghide picks its embedding positions with a graph-matching algorithm and, on JPEG, tweaks DCT coefficients rather than walking bit planes in order. zsteg is built for PNG and BMP LSB analysis across every channel and bit-plane combination.

    Tried: Run strings milkslap.png hoping the flag appears as a plain ASCII run inside the file.

    strings looks for contiguous printable ASCII in the raw bytes, but LSB steganography spreads each bit of the message across the least significant bit of successive pixel bytes. The flag characters are never contiguous, since seven bits of surrounding pixel data sit between each one, so strings finds nothing. zsteg reassembles those scattered bits in order.

    Learn more

    LSB steganography (Least Significant Bit) hides data by replacing the lowest bit of each pixel color channel with a bit of the secret message. Because the change is at most 1 step across the 256 possible values of each 8-bit channel, it is virtually invisible to the human eye but detectable with the right tools.

    zsteg is a Ruby-based tool specifically designed to detect various steganographic methods in PNG and BMP files. It tries multiple combinations: different bit planes (LSB, bit 1, bit 2...), different color channels (R, G, B, A), different byte orderings, and both row and column scans. Its output shows detected data along with the method used to extract it.

    If zsteg is not available, you can use stegsolve (a Java application) to manually examine different bit planes visually. Alternatively, steghide handles JPEG, BMP, WAV, and AU carriers. For a purely manual approach, a Python script using PIL can extract LSB values: pixel[0] & 1 gives the red channel LSB of each pixel.

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{imag3_m4n1pul4t10n_sl4p5}

The flag was hidden in the least significant bits of the image's pixel data - a classic LSB steganography technique that is imperceptible to the naked eye.

Key takeaway

Image formats store pixel data as discrete numeric values per channel, and the least significant bit of each contributes almost nothing to what you see while still carrying a payload. LSB steganography is among the most common covert channels because the statistical deviation it introduces is small and invisible without the right tools. zsteg and stegsolve automate the search across bit planes and channel orderings, and the same approach carries to audio, where the lowest bits of PCM samples are equally imperceptible.

Related reading

Useful tools for Forensics

Where to go next