| .. | ||
| README.md | ||
Accela Signal -- Solution
Overview
A LoRa-like Chirp Spread Spectrum (CSS) IQ stream containing two types of frames: beacon (cleartext) and data (XOR-encrypted flag). Players must implement CSS demodulation from scratch to decode the frames.
Steps
1. Capture IQ Stream
Connect to TCP port 9002. A text banner appears first, followed by raw IQ data.
nc HOST 9002 > capture.raw
# Or use the solve script
The banner tells you: IQ baseband, 8000 sps, int16 LE interleaved.
2. Analyze the Signal
Open the IQ data in a spectrogram tool (e.g., inspectrum, Python matplotlib, or GNU Radio). You'll see:
- Characteristic chirp patterns: frequency sweeps from low to high
- Repeating preambles (identical chirps)
- Gaps of noise between transmissions
This is Chirp Spread Spectrum (CSS), the modulation used by LoRa.
3. Determine Parameters
- Each chirp spans 128 samples → N = 128
- Since N = 2^SF → SF = 7 (spreading factor)
- Bandwidth = sample rate = 8000 Hz (baseband at Nyquist)
- 7 bits per symbol
4. Implement Dechirping
The key to CSS demodulation is dechirping:
-
Generate the base upchirp (symbol 0):
x0[n] = exp(j * π * n²/N) for n = 0..127 -
To decode a received chirp, multiply by the conjugate of the base chirp:
dechirped[n] = received[n] * conj(x0[n]) -
Take the DFT/FFT of the dechirped signal. The peak bin = symbol value.
5. Detect Frames
Frame structure:
[Preamble: 8× symbol 0] [Sync: 2× downchirp] [Header: 1 symbol] [Payload: L symbols]
- Preamble: 8 consecutive chirps all decoding to symbol 0
- Sync: 2 downchirps (conjugate of upchirps)
- Header: 1 symbol = payload length in bytes (Gray-coded)
- Payload: L symbols encoding the data bytes
6. Gray Decoding
Symbol values are Gray-coded (like real LoRa). After finding the FFT peak bin, apply inverse Gray code:
def gray_decode(val):
mask = val
while mask:
mask >>= 1
val ^= mask
return val
7. Symbol-to-Byte Unpacking
Each symbol carries 7 bits (SF=7). Concatenate all bits from decoded symbols, then group into 8-bit bytes.
8. Parse Frame Payload
Payload format: [type:1] [data:L] [crc16:2]
- Type 0x01 = beacon (ASCII text, for verification)
- Type 0x02 = data (XOR-encrypted flag)
- CRC-16 CCITT validates the payload
9. Decrypt Flag
The data frame's content is XOR'd with the repeating key "L41N" (4 bytes).
xor_key = b"L41N"
flag = bytes(b ^ xor_key[i % 4] for i, b in enumerate(encrypted_data))
Key Insights
- CSS/LoRa modulation encodes data as cyclic frequency shifts of a chirp signal
- The dechirp + FFT technique converts the frequency-domain problem into a simple peak detection
- Gray coding ensures that adjacent symbols (close FFT bins) differ by only 1 bit, reducing errors
- The 7-bit symbol → 8-bit byte packing is standard for non-byte-aligned symbol sizes
- The banner hints at CSS ("Chirp Spread Spectrum detected") to point players in the right direction
Flag
ESPILON{4cc3l4_ch1rp_spr34d_w1r3d}
Author
Eun0us