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.
Setup
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
pip3 install numpy pillow soundfile scipy# Install a command-line Python SSTV decoderSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Decode the SSTV audio files with Python
ObservationThe 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.pythonpython3 sstv_decode.py message.wav -o decoded_message.pngpythonpython3 sstv_decode.py clue1.wav -o clue1.pngpythonpython3 sstv_decode.py clue2.wav -o clue2.pngpythonpython3 sstv_decode.py clue3.wav -o clue3.pngExpected 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.
Step 2Read the clue images to find the steghide password
ObservationDecoding 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.
Step 3Extract the hidden data with steghide
ObservationClue 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.bashsteghide extract -sf message.wav -p 'hidden_stegosaurus' -xf flag.txtbashcat flag.txtWhat 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 passwordextracts data hidden with steghide. The-sfflag specifies the stego file, and-pprovides the passphrase. If no output filename is given, steghide writes to the filename stored at embed time;-xf flag.txtforces 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.