Try   HackMD

Write-Up - DGSE/ESIEE - 2020 - ASCII UART

Catégorie: Hardware

Enoncé

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 :).

Protocole UART

Avant de foncer tête baissée, il faut s'assurer d'avoir compris le protocol UART. Petit rappel:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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.

Analyse du fichier RAW

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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 !

Analyse d'un bloc RAW

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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:

  1. On vérifie le bit de parité pour vérifier l'intégrité de la trame
  2. Si la trame est bonne, on retire le bit de parité
  3. On inverse les 8 bits de données pour retrouver le LSB à droite

Exemple
Pour ce screen, on a la trame suivante 110010100 (sans les bits de START et STOP)

  1. Le nombre de bit à 1 est pair
  2. On retire le bit de parité: 11001010
  3. On inverse l'octet: 01010011 qui correspond à 'S' en ASCII

Maintenant, il ne reste plus qu'a écrire un petit script permettant de faire ça pour tous les blocs de données.

Pseudo-code

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/ }