$ file mystery.wav
mystery.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz $ strings mystery.wav | grep -i "flag\|ctf\|pico"
(no output)
# Flag was embedded visually in the spectrogram, not as ASCII bytes # Opened in Audacity, waveform view
# Pressed play — heard static and what sounded like garbled tones
# Tried Effect → Amplify (3x)
# Still just louder static
# Tried Effect → Noise Reduction
# Reduced the noise. Still nothing obvious.
# Tried Effect → Reverse
# Backwards static
# Tried Effect → Change Speed → 50%
# Slower backwards static
# Inspected the left and right channels separately (Split Stereo Track)
# Both channels had the same static
# Ran strings again on exported raw bytes
# Still nothing
# --- 20 minutes in ---
# Switched to Spectrogram view (finally)
# Saw the flag immediately in large block letters between 2000-4000 Hz
# picoCTF{...} — done, instantly
$ file mystery.wav
mystery.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz $ strings mystery.wav | grep -i "flag\|ctf\|pico"
(no output)
# Flag was embedded visually in the spectrogram, not as ASCII bytes # Opened in Audacity, waveform view
# Pressed play — heard static and what sounded like garbled tones
# Tried Effect → Amplify (3x)
# Still just louder static
# Tried Effect → Noise Reduction
# Reduced the noise. Still nothing obvious.
# Tried Effect → Reverse
# Backwards static
# Tried Effect → Change Speed → 50%
# Slower backwards static
# Inspected the left and right channels separately (Split Stereo Track)
# Both channels had the same static
# Ran strings again on exported raw bytes
# Still nothing
# --- 20 minutes in ---
# Switched to Spectrogram view (finally)
# Saw the flag immediately in large block letters between 2000-4000 Hz
# picoCTF{...} — done, instantly
$ file mystery.wav
mystery.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz $ strings mystery.wav | grep -i "flag\|ctf\|pico"
(no output)
# Flag was embedded visually in the spectrogram, not as ASCII bytes # Opened in Audacity, waveform view
# Pressed play — heard static and what sounded like garbled tones
# Tried Effect → Amplify (3x)
# Still just louder static
# Tried Effect → Noise Reduction
# Reduced the noise. Still nothing obvious.
# Tried Effect → Reverse
# Backwards static
# Tried Effect → Change Speed → 50%
# Slower backwards static
# Inspected the left and right channels separately (Split Stereo Track)
# Both channels had the same static
# Ran strings again on exported raw bytes
# Still nothing
# --- 20 minutes in ---
# Switched to Spectrogram view (finally)
# Saw the flag immediately in large block letters between 2000-4000 Hz
# picoCTF{...} — done, instantly
# In Audacity:
# 1. Track dropdown → Spectrogram
# 2. Track dropdown → Spectrogram Settings
# - Window size: try 1024, then 2048, then 4096
# - Max frequency: try 8000, then 20000
# - Color scheme: Spectrum or Inferno
# 3. Zoom in on the time axis if the flag appears compressed # If a QR code is visible in the spectrogram:
# Screenshot it → use a QR scanner
# The QR code may need cleanup in an image editor first if it's faint
# In Audacity:
# 1. Track dropdown → Spectrogram
# 2. Track dropdown → Spectrogram Settings
# - Window size: try 1024, then 2048, then 4096
# - Max frequency: try 8000, then 20000
# - Color scheme: Spectrum or Inferno
# 3. Zoom in on the time axis if the flag appears compressed # If a QR code is visible in the spectrogram:
# Screenshot it → use a QR scanner
# The QR code may need cleanup in an image editor first if it's faint
# In Audacity:
# 1. Track dropdown → Spectrogram
# 2. Track dropdown → Spectrogram Settings
# - Window size: try 1024, then 2048, then 4096
# - Max frequency: try 8000, then 20000
# - Color scheme: Spectrum or Inferno
# 3. Zoom in on the time axis if the flag appears compressed # If a QR code is visible in the spectrogram:
# Screenshot it → use a QR scanner
# The QR code may need cleanup in an image editor first if it's faint
# In Audacity waveform view:
# 1. Zoom in on the time axis (Ctrl+Scroll)
# 2. Look for repeating short/long pulses
# 3. Amplify if pulses are hard to distinguish (Effect → Amplify)
# 4. Apply Noise Reduction first if background noise obscures the pattern # For cleaner decoding: export as WAV, use online Morse decoder
# or: Effect → Normalize first to even out amplitude variations # Common mistake: mis-identifying the dot/dash boundary
# Short burst = dot, long burst = dash, long gap = letter boundary
# Very long gap = word boundary
# In Audacity waveform view:
# 1. Zoom in on the time axis (Ctrl+Scroll)
# 2. Look for repeating short/long pulses
# 3. Amplify if pulses are hard to distinguish (Effect → Amplify)
# 4. Apply Noise Reduction first if background noise obscures the pattern # For cleaner decoding: export as WAV, use online Morse decoder
# or: Effect → Normalize first to even out amplitude variations # Common mistake: mis-identifying the dot/dash boundary
# Short burst = dot, long burst = dash, long gap = letter boundary
# Very long gap = word boundary
# In Audacity waveform view:
# 1. Zoom in on the time axis (Ctrl+Scroll)
# 2. Look for repeating short/long pulses
# 3. Amplify if pulses are hard to distinguish (Effect → Amplify)
# 4. Apply Noise Reduction first if background noise obscures the pattern # For cleaner decoding: export as WAV, use online Morse decoder
# or: Effect → Normalize first to even out amplitude variations # Common mistake: mis-identifying the dot/dash boundary
# Short burst = dot, long burst = dash, long gap = letter boundary
# Very long gap = word boundary
# Reverse: Effect → Reverse (applies to selected region or entire track)
# Play again — if it now sounds like speech, you found it # Speed manipulation:
# Effect → Change Speed (try 50% for sped-up audio, 200% for slowed-down)
# Effect → Change Tempo (preserves pitch while changing speed)
# Effect → Change Pitch (changes pitch without affecting speed) # Common pattern: audio recorded at 2x speed
# Sounds like chipmunk speech → Change Speed → 50% → intelligible message # Another pattern: audio pitch-shifted up by an octave
# Change Pitch → -12 semitones → back to normal range
# Reverse: Effect → Reverse (applies to selected region or entire track)
# Play again — if it now sounds like speech, you found it # Speed manipulation:
# Effect → Change Speed (try 50% for sped-up audio, 200% for slowed-down)
# Effect → Change Tempo (preserves pitch while changing speed)
# Effect → Change Pitch (changes pitch without affecting speed) # Common pattern: audio recorded at 2x speed
# Sounds like chipmunk speech → Change Speed → 50% → intelligible message # Another pattern: audio pitch-shifted up by an octave
# Change Pitch → -12 semitones → back to normal range
# Reverse: Effect → Reverse (applies to selected region or entire track)
# Play again — if it now sounds like speech, you found it # Speed manipulation:
# Effect → Change Speed (try 50% for sped-up audio, 200% for slowed-down)
# Effect → Change Tempo (preserves pitch while changing speed)
# Effect → Change Pitch (changes pitch without affecting speed) # Common pattern: audio recorded at 2x speed
# Sounds like chipmunk speech → Change Speed → 50% → intelligible message # Another pattern: audio pitch-shifted up by an octave
# Change Pitch → -12 semitones → back to normal range
# Split stereo: Track dropdown → Split Stereo Track
# Two separate mono tracks appear — listen to each independently # Invert and mix trick (reveals phase-cancelled content):
# 1. Duplicate the track
# 2. On one copy: Effect → Invert
# 3. Select both tracks → Tracks → Mix → Mix and Render
# Content common to both channels cancels out; unique content remains # Also try: select all → Edit → Preferences → check for mono downmix differences
# Split stereo: Track dropdown → Split Stereo Track
# Two separate mono tracks appear — listen to each independently # Invert and mix trick (reveals phase-cancelled content):
# 1. Duplicate the track
# 2. On one copy: Effect → Invert
# 3. Select both tracks → Tracks → Mix → Mix and Render
# Content common to both channels cancels out; unique content remains # Also try: select all → Edit → Preferences → check for mono downmix differences
# Split stereo: Track dropdown → Split Stereo Track
# Two separate mono tracks appear — listen to each independently # Invert and mix trick (reveals phase-cancelled content):
# 1. Duplicate the track
# 2. On one copy: Effect → Invert
# 3. Select both tracks → Tracks → Mix → Mix and Render
# Content common to both channels cancels out; unique content remains # Also try: select all → Edit → Preferences → check for mono downmix differences
# In spectrogram view, DTMF tones appear as brief horizontal lines
# occurring simultaneously at two frequencies:
# 697 Hz + 1209 Hz = "1"
# 697 Hz + 1336 Hz = "2"
# 697 Hz + 1477 Hz = "3"
# 770 Hz + 1209 Hz = "4"
# ... (standard DTMF table) # Export the audio and use a DTMF decoder:
# $ multimon-ng -t wav -a DTMF mystery.wav
# Output: DTMF: 1 DTMF: 3 DTMF: 3 7 ...
# In spectrogram view, DTMF tones appear as brief horizontal lines
# occurring simultaneously at two frequencies:
# 697 Hz + 1209 Hz = "1"
# 697 Hz + 1336 Hz = "2"
# 697 Hz + 1477 Hz = "3"
# 770 Hz + 1209 Hz = "4"
# ... (standard DTMF table) # Export the audio and use a DTMF decoder:
# $ multimon-ng -t wav -a DTMF mystery.wav
# Output: DTMF: 1 DTMF: 3 DTMF: 3 7 ...
# In spectrogram view, DTMF tones appear as brief horizontal lines
# occurring simultaneously at two frequencies:
# 697 Hz + 1209 Hz = "1"
# 697 Hz + 1336 Hz = "2"
# 697 Hz + 1477 Hz = "3"
# 770 Hz + 1209 Hz = "4"
# ... (standard DTMF table) # Export the audio and use a DTMF decoder:
# $ multimon-ng -t wav -a DTMF mystery.wav
# Output: DTMF: 1 DTMF: 3 DTMF: 3 7 ...
# Audacity can't decode SSTV — use it to visualize and confirm the pattern,
# then export and decode externally: # On Linux:
# $ -weight: 500;">apt -weight: 500;">install qsstv
# Open qsstv → set to receive from audio file → play the wav
# OR use an online SSTV decoder (upload the wav file) # SSTV spectrogram signature: regular vertical stripes with
# a calibration "VIS code" tone at the beginning
# Audacity can't decode SSTV — use it to visualize and confirm the pattern,
# then export and decode externally: # On Linux:
# $ -weight: 500;">apt -weight: 500;">install qsstv
# Open qsstv → set to receive from audio file → play the wav
# OR use an online SSTV decoder (upload the wav file) # SSTV spectrogram signature: regular vertical stripes with
# a calibration "VIS code" tone at the beginning
# Audacity can't decode SSTV — use it to visualize and confirm the pattern,
# then export and decode externally: # On Linux:
# $ -weight: 500;">apt -weight: 500;">install qsstv
# Open qsstv → set to receive from audio file → play the wav
# OR use an online SSTV decoder (upload the wav file) # SSTV spectrogram signature: regular vertical stripes with
# a calibration "VIS code" tone at the beginning
# Spectrogram approach:
# Two horizontal bands alternating = binary encoding
# Note which frequency = 1, which = 0 (try both interpretations)
# Count pulse durations to determine bit boundaries
# Extract sequence: e.g., 01110000 01101001 01100011 01101111 = "pico" # Tip: if the binary doesn't decode to ASCII, try:
# - Reversing the bit order within each byte
# - Swapping the 1/0 frequency assignment
# - Reading right-to-left instead of left-to-right
# Spectrogram approach:
# Two horizontal bands alternating = binary encoding
# Note which frequency = 1, which = 0 (try both interpretations)
# Count pulse durations to determine bit boundaries
# Extract sequence: e.g., 01110000 01101001 01100011 01101111 = "pico" # Tip: if the binary doesn't decode to ASCII, try:
# - Reversing the bit order within each byte
# - Swapping the 1/0 frequency assignment
# - Reading right-to-left instead of left-to-right
# Spectrogram approach:
# Two horizontal bands alternating = binary encoding
# Note which frequency = 1, which = 0 (try both interpretations)
# Count pulse durations to determine bit boundaries
# Extract sequence: e.g., 01110000 01101001 01100011 01101111 = "pico" # Tip: if the binary doesn't decode to ASCII, try:
# - Reversing the bit order within each byte
# - Swapping the 1/0 frequency assignment
# - Reading right-to-left instead of left-to-right
# Audacity can only flag this as suspicious — the waveform looks mostly clean
# but with an unusual noise pattern in quiet sections. # Extract with external tools:
# $ -weight: 500;">pip -weight: 500;">install stegolsb
# $ wavsteg -r -i mystery.wav -o output.txt -n 1 -b 1000
# OR
# $ python3 -c "
# from scipy.io import wavfile
# import numpy as np
# rate, data = wavfile.read('mystery.wav')
# bits = (data.flatten() & 1).tolist()
# chars = [chr(int(''.join(map(str,bits[i:i+8])),2)) for i in range(0,min(len(bits),800),8)]
# print(''.join(chars))
# "
# Audacity can only flag this as suspicious — the waveform looks mostly clean
# but with an unusual noise pattern in quiet sections. # Extract with external tools:
# $ -weight: 500;">pip -weight: 500;">install stegolsb
# $ wavsteg -r -i mystery.wav -o output.txt -n 1 -b 1000
# OR
# $ python3 -c "
# from scipy.io import wavfile
# import numpy as np
# rate, data = wavfile.read('mystery.wav')
# bits = (data.flatten() & 1).tolist()
# chars = [chr(int(''.join(map(str,bits[i:i+8])),2)) for i in range(0,min(len(bits),800),8)]
# print(''.join(chars))
# "
# Audacity can only flag this as suspicious — the waveform looks mostly clean
# but with an unusual noise pattern in quiet sections. # Extract with external tools:
# $ -weight: 500;">pip -weight: 500;">install stegolsb
# $ wavsteg -r -i mystery.wav -o output.txt -n 1 -b 1000
# OR
# $ python3 -c "
# from scipy.io import wavfile
# import numpy as np
# rate, data = wavfile.read('mystery.wav')
# bits = (data.flatten() & 1).tolist()
# chars = [chr(int(''.join(map(str,bits[i:i+8])),2)) for i in range(0,min(len(bits),800),8)]
# print(''.join(chars))
# "
$ binwalk mystery.wav
DECIMAL HEXADECIMAL DESCRIPTION
0 0x0 RIFF (little-endian) data, WAVE audio
1048576 0x100000 Zip archive data, at least v2.0 # Zip appended after the audio — extract with dd or binwalk -e
$ dd if=mystery.wav of=hidden.zip bs=1 skip=1048576
$ binwalk mystery.wav
DECIMAL HEXADECIMAL DESCRIPTION
0 0x0 RIFF (little-endian) data, WAVE audio
1048576 0x100000 Zip archive data, at least v2.0 # Zip appended after the audio — extract with dd or binwalk -e
$ dd if=mystery.wav of=hidden.zip bs=1 skip=1048576
$ binwalk mystery.wav
DECIMAL HEXADECIMAL DESCRIPTION
0 0x0 RIFF (little-endian) data, WAVE audio
1048576 0x100000 Zip archive data, at least v2.0 # Zip appended after the audio — extract with dd or binwalk -e
$ dd if=mystery.wav of=hidden.zip bs=1 skip=1048576
# Step 1: What's the file format?
file target.wav
strings target.wav | grep -i "flag\|ctf\|pico" # Step 2: Check for appended data (before even opening Audacity)
binwalk target.wav # Step 3: Open in Audacity — spectrogram FIRST
# Track dropdown → Spectrogram
# Adjust: Window size 1024 → 2048 → 4096 until content is clear
# Adjust: Max frequency 8000 → 20000 if the default range shows nothing # Step 4: If spectrogram shows nothing obvious
# - Split stereo channels, check each independently
# - Try invert + mix to reveal phase-cancelled content
# - Switch to waveform: look for Morse-like pulse patterns # Step 5: If the audio sounds wrong
# - Effect → Reverse (backwards speech)
# - Effect → Change Speed → 50% (double-speed audio)
# - Effect → Change Pitch → -12 semitones (octave-shifted) # Step 6: If all else fails, export and use external tools
# - DTMF: multimon-ng -t wav -a DTMF target.wav
# - SSTV: qsstv or online decoder
# - LSB: wavsteg or manual Python extraction
# Step 1: What's the file format?
file target.wav
strings target.wav | grep -i "flag\|ctf\|pico" # Step 2: Check for appended data (before even opening Audacity)
binwalk target.wav # Step 3: Open in Audacity — spectrogram FIRST
# Track dropdown → Spectrogram
# Adjust: Window size 1024 → 2048 → 4096 until content is clear
# Adjust: Max frequency 8000 → 20000 if the default range shows nothing # Step 4: If spectrogram shows nothing obvious
# - Split stereo channels, check each independently
# - Try invert + mix to reveal phase-cancelled content
# - Switch to waveform: look for Morse-like pulse patterns # Step 5: If the audio sounds wrong
# - Effect → Reverse (backwards speech)
# - Effect → Change Speed → 50% (double-speed audio)
# - Effect → Change Pitch → -12 semitones (octave-shifted) # Step 6: If all else fails, export and use external tools
# - DTMF: multimon-ng -t wav -a DTMF target.wav
# - SSTV: qsstv or online decoder
# - LSB: wavsteg or manual Python extraction
# Step 1: What's the file format?
file target.wav
strings target.wav | grep -i "flag\|ctf\|pico" # Step 2: Check for appended data (before even opening Audacity)
binwalk target.wav # Step 3: Open in Audacity — spectrogram FIRST
# Track dropdown → Spectrogram
# Adjust: Window size 1024 → 2048 → 4096 until content is clear
# Adjust: Max frequency 8000 → 20000 if the default range shows nothing # Step 4: If spectrogram shows nothing obvious
# - Split stereo channels, check each independently
# - Try invert + mix to reveal phase-cancelled content
# - Switch to waveform: look for Morse-like pulse patterns # Step 5: If the audio sounds wrong
# - Effect → Reverse (backwards speech)
# - Effect → Change Speed → 50% (double-speed audio)
# - Effect → Change Pitch → -12 semitones (octave-shifted) # Step 6: If all else fails, export and use external tools
# - DTMF: multimon-ng -t wav -a DTMF target.wav
# - SSTV: qsstv or online decoder
# - LSB: wavsteg or manual Python extraction - Window size: Start with 1024. If the image looks blurry, go to 2048 or 4096. Larger window = sharper frequency resolution, slower time resolution
- Maximum frequency: Default is 8000 Hz. Try 20000 Hz if the flag isn't visible in the lower range — some challenges embed content in the higher frequencies precisely because the default view hides them
- Color scheme: "Spectrum" or "Inferno" tends to make hidden content more visible than the default grayscale