FCSC 2021 - Intro - File format
Lorsqu’un signal radio est représenté numériquement, il est composé d’une suite d’échantillons. L’une des méthodes d’échantillonnage très utilisée est l’échantillonnage I/Q, où chaque échantillon est représenté par une composante I (composante de phase) et une composante Q (composante de quadrature).
L’une des représentations numérique d’un signal I/Q supportée par les principaux outils est d’avoir une succession d’échantillons, avec chaque composante I et Q de chaque échantillon représentée par un nombre flottant compris entre 0 et 1, sur 32 bits, en mode petit-boutiste.
Le schéma ci-dessous montre ce format :
+-------+-------+-------+-------+-------+-------+ +-------+-------+
| i_0 | q_0 | i_1 | q_1 | i_2 | q_2 | ... | i_n | q_n |
| (f32) | (f32) | (f32) | (f32) | (f32) | (f32) | ... | (f32) | (f32) |
+-------+-------+-------+-------+-------+-------+ +-------+-------+
Le fichier challenge.iq
contient un signal représenté sous la forme décrite plus haut. Vous devez séparer les composantes I et Q et calculer le hash SHA256 résultant :
hash = SHA256(i_0 | i_1 | ... | i_n | q_0 | q_1 | ... | q_n)
flag = FCSC{<hash>}
SHA256(challenge.iq
) = fe4ea6b35841a0107555f1eb18c9f2fbcdef848116750040c2a80c384e6be932
.
Fichiers joints :
Résolution
Comme expliqué dans le challenge, le format de fichier IQ est une suite de paires de valeurs (I,Q) sur 32 bits. Nous devons lire le fichier challenge.iq de manière à concaténer toutes les valeurs de phase puis toutes les valeurs de quadrature à la suite (sans alternance I,Q).
Pour faire cela, nous allons écrire un script python pour lire les valeurs I,Q du fichier et les ajouter dans des listes séparées au fur et à mesure. Nous lisons à chaque fois un entier non signé sur 32 bits, représenté par le format I
dans la librairie python struct
(https://docs.python.org/3/library/struct.html#format-characters) :
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct
import hashlib
struct_fmt = 'I' # Format of an unsigned int
struct_len = struct.calcsize(struct_fmt)
struct_unpack = struct.Struct(struct_fmt).unpack_from
results = {'I':[],'Q':[]}
with open('challenge.iq', "rb") as f:
while True:
data = f.read(struct_len)
if not data: break
results['I'].append((data,struct.Struct(struct_fmt).unpack_from(data)))
data = f.read(struct_len)
if not data: break
results['Q'].append((data,struct.Struct(struct_fmt).unpack_from(data)))
rawdata = b''.join([e[0] for e in results['I']] + [e[0] for e in results['Q']])
hash = hashlib.sha256(rawdata).hexdigest()
print("FCSC{%s}" % hash)
Nous n’avons plus qu’à lancer le script :
$ ./solve.py
FCSC{843161934a8e53da8723047bed55e604e725160b868abb74612e243af94345d7}
Et nous obtenons le flag :
FCSC{843161934a8e53da8723047bed55e604e725160b868abb74612e243af94345d7}