Space Radio
Premier challenge de radio pour ma part, qui fait écho à mes cours de systèmes de transmission à l'Efrei...
Description du challenge
- Nom du CTF : 404CTF 2025
- Catégorie : Radio, Hardware
- Difficulté : Facile
- Date : Mai 2025
On nous donne le challenge suivant :
Fichier à démoduler : chall.iq
Analyse préliminaire
On nous informe que le challenge consiste à démoduler un signal FM. On sait aussi que la fréquence d'échantillonage est de 48 kHz.
Démodulation avec Python
On peut utiliser les bibliothèque scipy
et numpy
pour démoduler le signal :
import numpy as np
from scipy import signal
from scipy.io import wavfile
from pathlib import Path
def demodulate_fm(iq_data, fs, deviation=75000.0):
"""
Démodule un signal FM à partir de données IQ complexes
Args:
iq_data: Données IQ complexes
fs: Fréquence d'échantillonnage (Hz)
deviation: Déviation de fréquence maximale (Hz)
Returns:
Signal audio démodulé
"""
# Calcule la dérivée de phase instantanée (fréquence instantanée)
# Pour un signal FM, la fréquence instantanée est proportionnelle au signal modulant
diff_phase = np.diff(np.unwrap(np.angle(iq_data)))
# Normalisation par rapport à la déviation de fréquence et la fréquence d'échantillonnage
audio = diff_phase * (fs / (2 * np.pi * deviation))
return audio
def process_iq_file(file_path, fs=48000):
"""
Traite un fichier IQ et démodule le signal FM
Args:
file_path: Chemin vers le fichier IQ
fs: Fréquence d'échantillonnage (Hz)
"""
print(f"Traitement du fichier: {file_path}")
print(f"Fréquence d'échantillonnage: {fs} Hz")
try:
# Lecture du fichier IQ (format supposé: nombres complexes interleaved en float32)
iq_data = np.fromfile(file_path, dtype=np.complex64)
print(f"Nombre d'échantillons IQ: {len(iq_data)}")
# Démodulation FM
audio = demodulate_fm(iq_data, fs)
# Appliquer un filtre passe-bas pour isoler le signal audio (typiquement < 15kHz)
cutoff = 15000 # Hz
nyquist = fs / 2
normal_cutoff = cutoff / nyquist
b, a = signal.butter(5, normal_cutoff, 'low')
audio_filtered = signal.filtfilt(b, a, audio)
# Normalisation du signal audio
audio_filtered = audio_filtered / np.max(np.abs(audio_filtered))
# Sauvegarde en fichier WAV
output_file = Path(file_path).with_suffix('.wav')
wavfile.write(output_file, fs, audio_filtered.astype(np.float32))
print(f"Signal démodulé sauvegardé dans: {output_file}")
except Exception as e:
print(f"Erreur lors du traitement du fichier: {e}")
if __name__ == "__main__":
process_iq_file("chall.iq")
On peut alors entendre le flag assez facilement dans le fichier .wav
.
FLAG
404CTF{32788739F83}