Skip to main content

HideToSee picoCTF 2023 Solution

Extract a hidden message from an image file and then decode it using a classic substitution cipher.

Published: April 26, 2023Updated: August 25, 2026

Description

Steghide without a passphrase extracts a ciphertext which must then be decoded with an Atbash cipher.

Use steghide to extract embedded data from the JPEG (no password needed).

Open the resulting encrypted.txt and run it through an Atbash substitution cipher.

bash
wget https://artifacts.picoctf.net/c/237/atbash.jpg
bash
steghide extract -sf atbash.jpg -p ''
bash
cat encrypted.txt

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Extract the payload
    Observation
    The challenge provides a JPEG and the name says something is concealed inside it. steghide is the standard tool for that, embedding and extracting data in JPEGs by nudging DCT coefficients.
    Run steghide extract -sf atbash.jpg -p ''. The -p '' flag passes an empty passphrase non-interactively (handy in scripts and CI), and steghide writes encrypted.txt to the current directory.
    What didn't work first

    Tried: Run zsteg on atbash.jpg to find hidden data.

    zsteg only analyzes PNG and BMP files using LSB (Least Significant Bit) techniques; it cannot read JPEG files at all and will error out. Steghide is the correct tool here because it uses DCT coefficient manipulation specific to JPEG, not LSB embedding.

    Tried: Run steghide extract -sf atbash.jpg without the -p '' flag and press Enter when prompted for a passphrase.

    Interactively, steghide waits for a passphrase and an empty Enter submits the empty string, which works. In a script, omitting the passphrase flag leaves steghide hanging on terminal input. Passing an empty passphrase explicitly works reliably either way.

    Learn more

    Steghide hides data inside JPEG and BMP images by slightly modifying the DCT (Discrete Cosine Transform) coefficients of a JPEG or the pixel values of a BMP. The changes are statistically designed to be imperceptible to the human eye and to pass chi-square steganalysis. Data is optionally encrypted with a passphrase before embedding; when no passphrase is set (as in this challenge), steghide still performs the embedding but uses an empty key, so supplying no password at extraction time succeeds.

    The -sf flag means "stego file" - the file that carries the hidden payload. Steghide embeds a small header inside the image that records the original filename and size of the payload, which is why it knows to write encrypted.txt on extraction. This header is itself hidden using the same statistical technique, so it does not appear in a hex dump.

    Common steghide detection methods include: looking for the tool's characteristic frequency distribution shifts, running stegdetect, or simply always attempting extraction with blank/common passwords on any JPEG encountered in a forensics challenge.

  2. Step 2Decode with Atbash
    Observation
    The extracted file is called encrypted.txt and the image itself is named atbash.jpg. The filename names the cipher, so apply that classical substitution to the ciphertext.
    Drop the ciphertext into CyberChef, apply the Atbash recipe, and copy the resulting picoCTF flag.
    Learn more

    Atbash is one of the oldest known ciphers, originally used to encode Hebrew scripture. The mapping reflects every letter to its mirror position: E(x) = 25 - x in zero-based indexing (A=0...Z=25). Because 25 - (25 - x) = x, the cipher is its own inverse - apply once to encrypt, again to decrypt.

    Mapping:  A  B  C  D  E  ... M N ... X  Y  Z
              |  |  |  |  |      | |     |  |  |
              Z  Y  X  W  V  ... N M ... C  B  A
    
    Worked example on 'krxlXGU':
      k(10) -> 25 - 10 = 15 -> 'p'
      r(17) -> 25 - 17 = 8  -> 'i'
      x(23) -> 25 - 23 = 2  -> 'c'
      l(11) -> 25 - 11 = 14 -> 'o'
      X(23) -> 25 - 23 = 2  -> 'C'   (case preserved)
      G(6)  -> 25 - 6  = 19 -> 'T'
      U(20) -> 25 - 20 = 5  -> 'F'
    Result: 'picoCTF' ... continue across the rest of the ciphertext for the body of the flag.
    
    Self-inverse property (round trip):
      krxlXGU  --atbash-->  picoCTF  --atbash-->  krxlXGU
    Two applications return the original, which is why one Atbash recipe in
    CyberChef both encrypts and decrypts; you never need a separate "decrypt"
    button.

    Atbash has zero key space (only one possible mapping), so it offers no real security. CTF challenges use it to test familiarity with classical ciphers. The challenge name hidetosee combines both techniques: hide (steghide) reveals something you need to see (decode).

Interactive tools
  • Password Steg (Encrypt & Decrypt)Password-protect a message with AES-GCM and PBKDF2-derived keys. Encode produces a base64 ciphertext you can hide in any carrier; decode recovers the original with the same password. Runs entirely in the browser.
  • Atbash CipherEncode or decode the Atbash mirror cipher (A↔Z) in one click. Self-inverse, no key required.

Flag

Reveal flag

picoCTF{atbash_crack_05...}

The challenge name is the hint; Atbash is the only transformation required.

Key takeaway

steghide embeds data by perturbing JPEG DCT coefficients in a statistically balanced way, which keeps the payload invisible to casual inspection and resistant to chi-square steganalysis. Atbash, by contrast, has a key space of exactly one: identify the cipher and the plaintext is determined, with nothing to brute-force. Layering a weak cipher over a steganographic carrier does not compound the security, since anyone who knows either technique peels both layers off in turn.

Related reading

Tools used in this challenge

Where to go next