Aller au contenu principal

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 :

Infos challenge

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}