ASK Me Again (dawgCTF 2025)
You’re given an SDR capture (ask.iq) containing an Amplitude‑Shift Keying (ASK)–modulated signal. Recover the binary stream, convert to ASCII and extract the flag.
Hint:
The file name
ask.iq→ ASK modulation.“Isn’t binary a great way to represent ASCII characters?” → it’s just on/off keyed bits.
1. File Format & I/Q Reconstruction
Determine sample format Try reading as 16‑bit signed integers—result: even number of samples, so it’s interleaved I/Q:
import numpy as np raw = np.fromfile('ask.iq', dtype=np.int16) assert len(raw) % 2 == 0, "Expected interleaved I/Q pairs"De‑interleave & normalize
i = raw[0::2].astype(np.float32) q = raw[1::2].astype(np.float32) # Normalize 16‑bit signed to ±1.0 iq = (i + 1j*q) / 32768.0
At this point, iq is a complex baseband signal where amplitude encodes our bits.
2. Envelope Detection
ASK = on/off carrier. Extract the instantaneous amplitude:
A quick peek at its min/max confirms two plateaus—carrier‑off (0) vs carrier‑on (≈1.38).
3. Threshold Slicing
Slice that analog envelope into a raw 0/1 stream:
Note: Without smoothing, you’ll see tiny 1–4 sample “blips” around every transition.
4. Suppress Jitter
To clean up those edge blips, apply a short moving average:
From here on we work with bits, a much cleaner boolean stream.
5. Calculating Samples‑Per‑Bit = 480
SDR capture rate: 48 000 samples/sec
Suspected baud rate: ~100 bits/sec (common low‑speed ASK)
$\text{samples per bit (SPB)} = \frac{48,000}{100} = 480$
We hard‑code:
6. Symbol Slicing & Majority Vote
Fold each block of 480 samples into one bit:
Now decoded_bits is a clean array of 0/1 values—one per transmitted bit.
7. Pack into ASCII Bytes
Truncate to a whole number of bytes:
Group & convert (MSB first):
9. Full, Self‑Contained Script
Save this as decode_ask.py:
Run:
Output: