Skip to main content

flags are stepic picoCTF 2025 Solution

The flag sits in a PNG's least significant bits, put there by the Stepic library, so use that tool to decode it.

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

Description

A seemingly harmless "Country Flags" gallery hides a covert message from the Upanzi Network. Inspect the list of flags, identify the odd entry, and extract the hidden data from its PNG.

Web

Spin up the challenge instance and browse the provided gallery URL.

Pull the page source with curl, then grep it for flags/ references to enumerate every linked image and spot the odd one.

Download the suspicious PNG and confirm it's a real image with file before running stego decoders.

bash
curl http://standard-pizzas.picoctf.net:<PORT_FROM_INSTANCE>/ -o index.html
bash
grep -oE 'flags/[a-zA-Z]+\.png' index.html | sort -u
bash
wget http://standard-pizzas.picoctf.net:<PORT_FROM_INSTANCE>/flags/upz.png
bash
file upz.png

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
The Introduction to Steganography Tools covers Stepic (used here) alongside zsteg, steghide, stegcracker, binwalk, and Stegsolve, and the CTF steganography primer explains LSB embedding from first principles.
  1. Step 1Spot the rogue flag
    Observation
    Every image in the gallery is named after a three-letter country code. Grep the page source for the image references and any slug that is not a real country stands out.
    Grep the page source for every flags/<name>.png reference. The output is mostly country codes - usa.png, fra.png, jpn.png, etc. - and one outlier upz.png. Upanzi is a fictional CyLab Africa nation, so its image is the embedded clue. Download it and run a stego decoder.
    bash
    grep -oE 'flags/[a-zA-Z]+\.png' index.html | sort -u
    bash
    # Output mostly country codes; upz.png stands out.
    bash
    wget http://standard-pizzas.picoctf.net:<PORT_FROM_INSTANCE>/flags/upz.png
    bash
    file upz.png
    bash
    # Should report: PNG image data, NNNxNNN, 8-bit/color RGBA, non-interlaced

    Expected output

    upz.png: PNG image data, 800 x 533, 8-bit/color RGBA, non-interlaced
    What didn't work first

    Tried: Manually scrolling through the rendered gallery page looking for a visually different flag image.

    upz.png is styled and sized like every other flag, so nothing about the rendered page gives it away. Grepping the HTML for image filenames exposes the odd slug at once.

    Tried: Running strings upz.png to look for the flag directly in the binary.

    LSB steganography spreads the payload across the lowest bits of individual pixel channels, never as a contiguous string. strings only finds runs of printable characters stored consecutively, so it misses this completely. Reconstructing the bit stream takes a dedicated decoder like stepic or zsteg.

    Learn more

    OSINT (Open Source Intelligence) and visual reconnaissance are important first steps in CTF challenges. When presented with a list of items, security researchers learn to look for anomalies - entries that don't belong, slightly misspelled names, unusual ordering, or references to fictional entities. "Upanzi" is a fictional African nation referenced in cybersecurity educational contexts, making it immediately suspicious in a list of real countries.

    Viewing page source is a fundamental web security technique. HTML comments, hidden form fields, unusual script tags, metadata, and data attributes often contain information that is not visible in the rendered page. Developers sometimes leave debug information, internal API endpoints, or - as in this challenge - clues to hidden functionality directly in the source code.

    The gallery structure is a common steganography delivery mechanism: embed a secret-carrying image among many innocuous images so that a casual observer sees only a normal image gallery. Finding the odd one out requires enumeration, which is why tools like curl combined with text search (grep) are useful for quickly scanning all entries programmatically rather than reading them visually.

  2. Step 2Install Stepic
    Observation
    The title puns on stepic, a Python LSB steganography library. That is what embedded the payload, so installing it gives you the matching decoder.
    Stepic is the Python LSB stego library the challenge name riffs on. Create a virtualenv and pip install stepic (Pillow comes in as a dependency, so you don't need to install it separately). If install fails, fall back to zsteg upz.png.
    python
    python3 -m venv venv && source venv/bin/activate
    bash
    pip install stepic   # pulls in Pillow automatically
    What didn't work first

    Tried: Running pip install stepic globally without a virtualenv and then calling stepic as a shell command.

    Stepic installs as a Python library, not a standalone shell binary. Without the virtualenv activated, the stepic command may not be on PATH. The correct invocation is python3 -m stepic or stepic only after activating the virtualenv where it was installed.

    Learn more

    LSB steganography (Least Significant Bit) hides data by replacing the lowest-order bit of each color channel in every pixel with bits from the secret message. The change is visually imperceptible because flipping the LSB changes a pixel's color value by only 1 out of 255. A red pixel at value 200 (11001000) becomes 201 (11001001) - completely indistinguishable to the human eye.

    Stepic is a Python library that encodes and decodes messages hidden in PNG images using LSB steganography. The -d flag (decode) reads the LSB of each channel pixel by pixel, reconstructs the binary stream, and interprets it as text. Note: Stepic only touches the R, G, and B channels (three payload bits per pixel) and ignores any alpha channel, so an RGBA PNG still carries its payload in the color bands. zsteg's bit-plane brute force covers those and more. It is a straightforward implementation that does not use passwords or additional encoding, making it easy to use but also easy to detect with forensic tools.

    Other popular LSB stego tools include zsteg (Ruby, scans multiple bit planes and color channel combinations), StegSolve (Java GUI tool that visualizes individual bit planes), and steghide (supports password-protected embedding in JPEG and BMP files). When a challenge does not specify which tool was used, zsteg is often the best first choice because it automatically tries many configurations.

  3. Step 3Decode the PNG
    Observation
    file confirms upz.png is a valid 8-bit RGBA PNG, and the challenge name names the encoder. Run stepic in decode mode over the pixel data.
    Run Stepic in decode mode against upz.png. It walks each pixel's low bits and prints the embedded ASCII flag. If the default zsteg fallback finds nothing, brute-force bit depths with zsteg -b. For paranoia, stegoVeritas upz.png --all runs statistical tests to confirm LSB embedding before you keep digging.
    bash
    stepic -d -i upz.png
    bash
    # Fallback if Stepic isn't installed:
    bash
    zsteg upz.png
    bash
    # zsteg tries multiple bit planes and encodings; if default misses, brute-force:
    bash
    zsteg upz.png -b 1,2,3,4
    What didn't work first

    Tried: Using steghide to decode the PNG with steghide extract -sf upz.png.

    Steghide only supports JPEG and BMP carrier formats, not PNG. Running it against upz.png produces an error about an unsupported file format. The challenge uses Stepic, which encodes LSB payloads specifically into PNG pixel channels. Use stepic or zsteg instead.

    Tried: Running stepic -e -i upz.png (encode flag) instead of stepic -d -i upz.png (decode flag).

    -e encodes a new message and wants one as an argument, so it prompts or errors out. -d decodes, reading the payload already in the image.

    Learn more

    The PNG format is particularly well-suited for steganography because it uses lossless compression. JPEG images use lossy compression, which discards fine-grained pixel differences during encoding - destroying LSB-embedded data in the process. PNG preserves every pixel value exactly, so LSB payloads survive saving and sharing. This is why most LSB steganography challenges use PNG or BMP files.

    Detecting LSB steganography statistically is possible through histogram analysis: LSB embedding creates subtle patterns in the distribution of pixel values that deviate from natural images. Tools like StegoVeritas and academic tools like StegExpose perform these statistical tests to detect the presence of hidden data without knowing the message content. In practice, simple single-bit LSB embedding is easily detected; more sophisticated algorithms like F5 and JPEG steganography with perceptual modeling are harder to detect.

    This challenge is a great introduction to the broader field of digital watermarking and information hiding, which has legitimate applications in copyright protection, covert communications research, and digital forensics (detecting when images have been modified or contain hidden content).

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

Any other LSB steganography decoder (zsteg, StegSolve, etc.) works too; the payload is short plaintext.

Key takeaway

LSB steganography works because the lowest bit of a pixel value is perceptually irrelevant: flipping it moves a color channel by one part in 255, well under what an eye can see. PNG's lossless compression preserves those changes exactly, which is why it is the carrier of choice, while JPEG destroys them. The same trick hides data in PCM audio samples, video frames, and packet payloads, and forensics catches it with statistical tests that find unnatural distributions in the bit plane.

Related reading

Useful tools for Forensics

Where to go next