FCSC 2021 - Intro - File format

Table des matières :

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}