Un informateur a intercepté un message binaire transmis sur un câble. Il a rapidement enregistré via la carte son d'un PC les données en 8 bits signés (ascii_uart.raw). Dans la précipitation, il a oublié de noter la fréquence d'échantillonnage. Retrouvez le message.
Le flag est de la forme DGSESIEE{X} avec X le message
Pour ce challenge, il était possible de passer par un éditeur de son numérique comme Audacity, pour extraire les informations binaires, ou de faire un petit script.
Je vais ici présenter la solution du script :).
Avant de foncer tête baissée, il faut s'assurer d'avoir compris le protocol UART. Petit rappel:
Une trame UART commence toujours par un bit de START à 0, suivit de 8 bits de données, plus optionnellement un bit de parité, puis finit par un bit de STOP à 1.
Comme on peut le voir sur un éditeur comme Visual Studio Code, le fichier est composé de suites incohérentes de caractères. Cependant, on remarque facilement qu'il n'y a que deux types de groupes d'octets. Des octets à caractères imprimables et l'autre groupe non imprimables.
Cela nous laisse penser que ces deux types de groupes représentent les bits 0 et 1. De plus, d'après ce que j'ai indiqué en rouge sur le screen, on remarque des blocs qui nous font drôlement penser à la structure des trames UART… On est sur une bonne piste !
Examinons plus en détail un de ces blocs pour vérifier cela !
Assez intuitivement, on remarque que les caractères non imprimables représentent un bit 0. Le premier bloc sélectionné correspond au bit START. Après avoir sélectionné ce sous-bloc, on remarque qu'il fait exactement 638 octets.
On essaye de faire 9 sous-blocs de 638, afin de voir si on arrive bien à la fin de ce bloc de données, et OUI, on arrive à l'octet qui représente le bit STOP à 1 !
Maintenant on sait qu'un bloc de ce genre représente bien une trame UART, et qui comporte même un bit de partité !
Afin d'extraire l'information de la trame, on procède ainsi:
Exemple
Pour ce screen, on a la trame suivante 110010100
(sans les bits de START et STOP)
11001010
01010011
qui correspond à 'S' en ASCIIMaintenant, il ne reste plus qu'a écrire un petit script permettant de faire ça pour tous les blocs de données.
Pour info, on a vu qu'un groupe de 638 octets de caractères imprimables correspond au bit 1, et un groupe du même nombre d'octets de caractères non-imprimables correspond au bit 0.
Avec un hexdump -C ascii_uart.raw
, on voit que les caractères imprimables sont des
octets < 0x80, et que les autres sont >= 0x80.
file = open("ascii_uart.raw", "rb")
flag = ""
Lire octet dans file tant qu'il n'est pas lu en entier:
Si l'octet lu >= 0x80: // START bit
Lire les 9 prochains blocs avec un pas de 638 octets
trame = concaténation des 9 bits des blocs
Verifier bit de parité
Si nombre de bit à 1 est impair:
continue
trame = retirerBitParite(trame)
trame = inverser(trame)
trame = ascii(trame)
flag += trame
Afficher flag
Flag = DGSESIEE{ d[--]b _(''/)/ (^_-) @}-;–- (_) \o/ }