Description
Something is tucked away inside a JPEG image. The title is a hint: the clue to extracting it is hiding in plain sight, right in the file's own metadata.
Setup
Download the JPG file from the challenge page.
Install exiftool and steghide: sudo apt install libimage-exiftool-perl steghide
sudo apt install libimage-exiftool-perl steghideSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Run exiftool to inspect the image metadataObservationI noticed the challenge title said the clue was hiding 'in plain sight' within the file itself, which suggested inspecting the image's metadata fields rather than the pixel data, making exiftool the natural first tool.Run exiftool on the downloaded image and look at the Comment field. Instead of a flag, you will find a base64-encoded string: c3RlZ2hpZGU6Y0VGNmVuZHZjbVE9. That string is the first clue.bashexiftool img.jpgWhat didn't work first
Tried: Opening the image in a hex editor or viewer to search for hidden text manually
Hex editors show raw bytes and viewers render pixels, but the EXIF Comment field is stored in a structured binary segment at the start of the JPEG that is easy to overlook without a parser. exiftool parses the IFD (Image File Directory) structure and labels every field by name, so the Comment field appears immediately labeled instead of buried in a wall of bytes.
Tried: Running strings on the image file to find the base64 comment
strings prints sequences of printable ASCII bytes and will show the base64 comment, but it also dumps dozens of other byte sequences from the JPEG header, ICC profile, and thumbnail data, making it hard to identify which string is meaningful. exiftool labels the field as Comment so there is no ambiguity about which string to decode.
Learn more
EXIF (Exchangeable Image File Format) is a standard for embedding structured metadata inside image files. Tags cover camera model, lens settings, GPS coordinates, timestamps, and a free-form
Commentfield that can hold arbitrary text.exiftoolby Phil Harvey reads every known metadata standard (EXIF, XMP, IPTC) across over 200 file formats and prints them as key-value pairs.The
Commentfield is completely free-form, making it a natural hiding spot in forensics challenges. In this case it holds a base64 string rather than the flag itself, which sets up the next layer of the puzzle.exiftool -Comment img.jpg- show only the Comment fieldexiftool -all= img.jpg- strip all metadata in place
Step 2
Double-decode the base64 comment to get the steghide passphraseObservationI noticed the exiftool Comment field contained the string c3RlZ2hpZGU6Y0VGNmVuZHZjbVE9, which is padded base64, and the first decode produced steghide:cEF6endvcmQ= showing yet another base64 suffix, which suggested a second decode was needed to recover the actual passphrase.Decode the comment string once: you getsteghide:cEF6endvcmQ=. The prefixsteghide:names the tool to use; the suffixcEF6endvcmQ=is another base64 string. Decode that second string to reveal the passphrase:pAzzword.bashecho "c3RlZ2hpZGU6Y0VGNmVuZHZjbVE9" | base64 -dbashecho "cEF6endvcmQ=" | base64 -dWhat didn't work first
Tried: Using the raw first-decode output steghide:cEF6endvcmQ= as the steghide passphrase directly
Passing the entire string including the colon and the second base64 blob as the passphrase produces a steghide decryption failure because the actual passphrase is only the decoded value of the second segment. The colon is a delimiter between the tool name and the encoded passphrase, not part of the secret itself.
Tried: Trying base64 -d on the original comment string and stopping after a single decode
One decode produces steghide:cEF6endvcmQ=, which looks like a result but is itself still partially encoded. Stopping here and treating cEF6endvcmQ= as the passphrase will cause steghide to reject it. A second decode of only the suffix cEF6endvcmQ= is required to obtain the actual plaintext passphrase pAzzword.
Learn more
Base64 encodes arbitrary binary data as printable ASCII characters, making it safe to embed in text fields like EXIF comments. Double encoding (base64 of base64) is a common trick in CTF challenges to add an extra layer of obfuscation. The first decode reveals the tool name and a second encoded blob; the second decode yields the actual passphrase.
The naming convention
tool:encodedPassphrasein the first decoded string is the challenge author giving you everything you need in one place: the tool to use and the secret to unlock it, separated by a colon.Step 3
Extract the hidden file with steghideObservationI noticed the first base64 decode explicitly named the tool as steghide in the format steghide:encodedPassphrase, and I now had the decoded passphrase pAzzword, which pointed directly to running steghide extract on the JPEG.Runsteghide extractwith the passphrasepAzzword. Steghide will write a file calledflag.txtto the current directory. Read that file to get the flag.bashsteghide extract -sf img.jpg -p pAzzwordbashcat flag.txtExpected output
picoCTF{h1dd3n_1n_1m4g3_...}What didn't work first
Tried: Running steghide extract without the -p flag and entering pAzzword at the interactive prompt but mis-capitalizing it
Steghide passphrases are case-sensitive. Typing pazzword or Pazzword instead of pAzzword causes a passphrase error and no output file is written. The exact mixed-case string pAzzword must be used, which is why decoding the base64 precisely rather than guessing is essential.
Tried: Using stegsolve or zsteg instead of steghide to extract the hidden data
Stegsolve and zsteg target LSB steganography in PNG bit planes and do not understand steghide's DCT-coefficient embedding format in JPEGs. They will report no hidden data or output garbage. The first decode of the EXIF comment explicitly names the tool as steghide, so the extraction must use steghide with the -sf flag and the recovered passphrase.
Learn more
Steghide is a steganography tool that conceals data by modifying the least-significant bits of a JPEG's DCT coefficients, the frequency-domain numbers that encode the image. The change is mathematically small and visually undetectable to the human eye, but the hidden bytes are perfectly recoverable with the correct passphrase. This is true steganography: the data is hidden inside the image content, not just in metadata.
The challenge title "hidden in plainsight" points to both layers: the passphrase is hiding in plain sight in the EXIF comment (if you know to look and decode it), while the flag itself is hidden inside the image using steghide.
steghide --info img.jpg- check whether steghide data is present without extractingsteghide extract -sf img.jpg- extract interactively (prompts for passphrase)steghide extract -sf img.jpg -p pAzzword- extract non-interactively with the passphrase
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{h1dd3n_1n_1m4g3_...}
The hash suffix in the flag is unique per challenge instance, so your flag will differ from others. The format is picoCTF{h1dd3n_1n_1m4g3_<hash>}.