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

  1. 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"
  2. 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

  1. Truncate to a whole number of bytes:

  2. Group & convert (MSB first):


9. Full, Self‑Contained Script

Save this as decode_ask.py:

Run:

Output: