Skip to main content

m00nwalk2 picoCTF 2019 Solution

Decode a layered audio signal using slow-scan television techniques to uncover the hidden flag.

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

Description

Revisit the first moonwalk transmission. This one has a hidden message inside - one decoded image contains clues and another contains the actual hidden flag, protected by a steganography password.

Download the WAV file(s) from the challenge.

Install a Python SSTV decoder (a command-line decoder that reads the WAV samples directly and writes a PNG).

Install steghide: sudo apt install steghide

bash
pip3 install numpy pillow soundfile scipy
bash
# Install a command-line Python SSTV decoder

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Decode the SSTV audio files with Python
    Observation
    The title is 'm00nwalk2' and the challenge gives WAV files, the same kind of signal used in the Apollo 11 transmissions. That means SSTV audio, and a Python SSTV library will decode the WAVs straight into images.
    Use a Python SSTV library to decode the WAV file(s). The library auto-detects the SSTV mode (Scottie 1, Martin 1, etc.) and outputs image files. Decode all WAV files provided.
    python
    python3 sstv_decode.py message.wav -o decoded_message.png
    python
    python3 sstv_decode.py clue1.wav -o clue1.png
    python
    python3 sstv_decode.py clue2.wav -o clue2.png
    python
    python3 sstv_decode.py clue3.wav -o clue3.png

    Expected output

    decoded_message.png, clue1.png, clue2.png, clue3.png
    What didn't work first

    Tried: Use QSSTV with a virtual audio loopback (e.g. PulseAudio loopback or VB-Cable) to decode the WAV file

    QSSTV needs a live audio input, so playing the WAV through a loopback adds timing drift and buffer underruns that corrupt the sync pulse, giving a skewed or entirely black image. The Python decoder reads the sample array straight from the file, so it gets a perfect bitstream and detects the VIS mode code reliably.

    Tried: Open the WAV file in Audacity and look for spectrogram patterns to manually read the image data

    A spectrogram shows the frequency-time structure of SSTV audio but decodes no pixel values; it only tells you a signal is there. Mapping spectrogram intensities to pixels by hand is impractical past a few pixels. A dedicated SSTV decoder is what reconstructs the actual image.

    Learn more

    SSTV (Slow Scan Television) encodes images as audio signals. Different SSTV modes (Scottie 1, Martin 1, Robot 36, etc.) use different image sizes, color orders, and timing. A Python decoder using scipy for signal processing can detect the mode automatically from the VIS code at the start of the audio.

  2. Step 2Read the clue images to find the steghide password
    Observation
    Decoding produces several images labeled as clue files alongside the main message. The clues are there to be read, and one of them should carry the steghide password for the next layer.
    The decoded clue images contain three hints. Clue 1 gives the steganography password: 'hidden_stegosaurus'. Clue 2 hints at steganography in audio (the quieter you are the more you can hear). Clue 3 mentions a steganography tool website. Combined, the clues tell you to run steghide on the original WAV file with the password 'hidden_stegosaurus'.
    Learn more

    Steghide can hide data inside image and audio files. For WAV files, it embeds data in the least significant bits of the audio samples without significantly changing the sound. The embedded data is password-protected.

  3. Step 3Extract the hidden data with steghide
    Observation
    Clue 2 hints at audio steganography ('the quieter you are the more you can hear'), clue 3 names a steganography tool, and clue 1 gives the password outright: hidden_stegosaurus. Together they point at running steghide on the original message.wav.
    Run steghide on the main WAV file using the password found in the clue images. The extracted file contains the flag.
    bash
    steghide extract -sf message.wav -p 'hidden_stegosaurus' -xf flag.txt
    bash
    cat flag.txt
    What didn't work first

    Tried: Run steghide on the decoded PNG images instead of the original WAV file

    steghide stores its payload in whichever file it embedded into. The PNGs came out of the SSTV decoder and hold image data only, so steghide extract returns a passphrase error or reports no data. The flag is embedded in message.wav, which is the carrier steghide actually wrote to.

    Tried: Try steghide without the -p flag and enter a blank password when prompted

    Steghide uses password-based encryption (Rijndael) to protect the hidden payload. An empty passphrase produces a different key than 'hidden_stegosaurus', so decryption fails and steghide reports 'passphrase is not correct'. The correct password comes from the clue1.png image decoded in the previous step.

    Learn more

    steghide extract -sf file -p password extracts data hidden with steghide. The -sf flag specifies the stego file, and -p provides the passphrase. If no output filename is given, steghide writes to the filename stored at embed time; -xf flag.txt forces the name so you always know what to read. The extracted file contains the flag.

    This challenge layered two steganography techniques: SSTV audio encoding (to hide the clue images inside audio) and steghide (to hide the flag inside the original WAV). Understanding that clues are often themselves encoded requires checking every artifact in the challenge.

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.

Flag

Reveal flag

picoCTF{the_answer_lies_hidden_in_plain_sight}

Decode the SSTV WAV files to get clue images, read the password 'hidden_stegosaurus' from clue 1, then run steghide extract on the main WAV file to get the flag.

Key takeaway

Layered steganography chains covert channels, so beating one layer only hands you instructions for the next. That mirrors real covert-communication tradecraft, where decoys and misdirection exist to slow an analyst down. The forensic habit worth building is treating every decoded artifact as a possible new container rather than a final answer. A password-protected steghide payload, inside SSTV audio, inside a WAV, is a good example of innocuous techniques combining into a well-hidden channel.

Related reading

Tools used in this challenge

Where to go next