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.
Setup
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.
curl http://standard-pizzas.picoctf.net:<PORT_FROM_INSTANCE>/ -o index.htmlgrep -oE 'flags/[a-zA-Z]+\.png' index.html | sort -uwget http://standard-pizzas.picoctf.net:<PORT_FROM_INSTANCE>/flags/upz.pngfile upz.pngSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Spot the rogue flag
ObservationEvery 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 everyflags/<name>.pngreference. The output is mostly country codes -usa.png,fra.png,jpn.png, etc. - and one outlierupz.png. Upanzi is a fictional CyLab Africa nation, so its image is the embedded clue. Download it and run a stego decoder.bashgrep -oE 'flags/[a-zA-Z]+\.png' index.html | sort -ubash# Output mostly country codes; upz.png stands out.bashwget http://standard-pizzas.picoctf.net:<PORT_FROM_INSTANCE>/flags/upz.pngbashfile upz.pngbash# Should report: PNG image data, NNNxNNN, 8-bit/color RGBA, non-interlacedExpected 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.pngto 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
curlcombined with text search (grep) are useful for quickly scanning all entries programmatically rather than reading them visually.Step 2Install Stepic
ObservationThe 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 andpip install stepic(Pillow comes in as a dependency, so you don't need to install it separately). If install fails, fall back tozsteg upz.png.pythonpython3 -m venv venv && source venv/bin/activatebashpip install stepic # pulls in Pillow automaticallyWhat didn't work first
Tried: Running
pip install stepicglobally without a virtualenv and then callingstepicas a shell command.Stepic installs as a Python library, not a standalone shell binary. Without the virtualenv activated, the
stepiccommand may not be on PATH. The correct invocation ispython3 -m stepicorstepiconly 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
-dflag (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.
Step 3Decode the PNG
Observationfile 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 withzsteg -b. For paranoia,stegoVeritas upz.png --allruns statistical tests to confirm LSB embedding before you keep digging.bashstepic -d -i upz.pngbash# Fallback if Stepic isn't installed:bashzsteg upz.pngbash# zsteg tries multiple bit planes and encodings; if default misses, brute-force:bashzsteg upz.png -b 1,2,3,4What 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 ofstepic -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.