Skip to main content

Freakquency

Challenge

Content preserved from the original writeup source. Minimal normalization was applied to fit platform format.

Solution

Original Writeup Content (Preserved)

Freakquency (UDCTF) Writeup

Initial Challenge Prompt

  • Name: Freakquency
  • Points: 100
  • Difficulty: Medium-Hard
  • Prompt: You have the audacity to match my freak?
  • Given file: hidden_message.wav

Challenge Summary

This challenge looks like digital audio at first glance (close tones around ~1.5 kHz can suggest FSK/phase-coded content), but the actual solve path is visual steganography in the spectrogram. The hidden payload appears as readable text in a higher frequency band.

Files

  • hidden_message.wav
  • spec_full.png (plus zoom/helper spectrogram images)

Solve Path

  1. Inspect audio metadata.
  2. Try decoder hypotheses (optional): low-shift FSK/clocked demod can be a false lead.
  3. Inspect full-band spectrogram with higher contrast.
  4. Read embedded Base64 string.
  5. Decode Base64 to recover the flag.

1) Inspect Audio

Commands:

file hidden_message.wav soxi hidden_message.wav

Relevant metadata:

  • Mono
  • 44100 Hz sample rate
  • 32-bit floating PCM
  • ~27 s duration

2) Spectrogram Forensics

Using the provided full spectrogram image (or generating one yourself), the hidden text is visible around the 4-6 kHz region.

Spectrogram Used and Why

We used an STFT spectrogram with these settings:

  • Fs: 44100 (original sample rate, no resampling)
  • NFFT: 2048
  • noverlap: 1024 (50% overlap)
  • cmap: gray (high contrast for bright text strokes)
  • y-limit: 0 to 22050 Hz (full Nyquist band)

Why these settings work well:

  • NFFT 2048 gives a useful balance between frequency detail and time sharpness. It is enough to make letter shapes readable in the 4-6 kHz band.
  • 50% overlap reduces blockiness and makes character edges smoother across time.
  • Full-band view avoids tunnel vision around ~1.5 kHz and exposes hidden content at higher frequencies.
  • Grayscale mapping improves legibility of faint strokes versus many rainbow colormaps.

Focused code for the spectrogram step:

#!/usr/bin/env python3 import matplotlib.pyplot as plt from scipy.io import wavfile

sr, data = wavfile.read("hidden_message.wav") if getattr(data, "ndim", 1) > 1: data = data[:, 0]

plt.figure(figsize=(16, 6)) plt.specgram(data, Fs=sr, NFFT=2048, noverlap=1024, cmap="gray") plt.ylim(0, 22050) plt.xlabel("Time (s)") plt.ylabel("Hz") plt.colorbar(label="dB") plt.tight_layout() plt.savefig("spec_fullband.png", dpi=200) print("saved spec_fullband.png")

Extracted text:

VURDVEZ7dzB3X3kwdV9jNG5faDM0cl80X2YxbDM/fQ==

Note on OCR pitfalls:

  • The tail is .../fQ== (slash then fQ), not .../v fQ== with a space.
  • Correct decode starts with UDCTF, not URCTF.

3) Decode Base64

One-liner:

echo 'VURDVEZ7dzB3X3kwdV9jNG5faDM0cl80X2YxbDM/fQ==' | base64 -d

Output:

UDCTF{w0w_y0u_c4n_h34r_4_f1l3?}

Full Solve Code (Reproducible)

#!/usr/bin/env python3
import base64
import argparse
import matplotlib.pyplot as plt
from scipy.io import wavfile

def make_spectrogram(path_in: str, path_out: str = "spec_out.png") -> None:
sr, data = wavfile.read(path_in)
if getattr(data, "ndim", 1) > 1:
data = data[:, 0]

plt.figure(figsize=(16, 6))
plt.specgram(data, Fs=sr, NFFT=2048, noverlap=1024, cmap="gray")
plt.ylim(0, 22050)
plt.xlabel("Time (s)")
plt.ylabel("Hz")
plt.colorbar(label="dB")
plt.tight_layout()
plt.savefig(path_out, dpi=200)
print(f"Saved spectrogram to {path_out}")

def decode_payload() -> str:
b64_payload = "VURDVEZ7dzB3X3kwdV9jNG5faDM0cl80X2YxbDM/fQ=="
return base64.b64decode(b64_payload).decode()

def main() -> None:
parser = argparse.ArgumentParser(description="Freakquency solver helper")
parser.add_argument("wav", nargs="?", default="hidden_message.wav", help="Input WAV file")
parser.add_argument("--spec-out", default="spec_out.png", help="Output spectrogram image")
args = parser.parse_args()

make_spectrogram(args.wav, args.spec_out)
print("Decoded flag:", decode_payload())

if __name__ == "__main__":
main()

Run it:

python3 solve_freakquency.py hidden_message.wav --spec-out spec_out.png

Final Flag

UDCTF{w0w_y0u_c4n_h34r_4_f1l3?}