S3cr37 4g3nt
Embedded (100 points)
Énoncé
En tant qu'agent spécial au service de la faction XXX vous devez décoder un message intercepté sur un théâtre d'opération entre deux agents ennemis. Pour ce faire, votre spécialiste radio vous livre le message (qui semble être chiffré) ainsi que le firmware d'un terminal de chiffrement malheureusement détruit. A vous de jouer agent XXX 007...
Dans cette épreuve, on nous fournissait un message chiffré ainsi qu'un binaire, cryptomachine.bin qui s'occupait de chiffrer un message.
Le message chiffré, lui, n'était rien d'autre qu'une chaîne hexadécimale :
49D29B3439B8FB013DE2F9FD35B8F8FD36E5F8FC3409FCFF352DA8033BEAA8F83B73FBFC373AAD003573FB026990FEFA65B8FCFE343AA90034E6AE013DE5AA2A6AA9AEFE81Solution
Cette épreuve faisait directement suite à une première épreuve de la catégorie Embedded, Defused. Je n'ai pas écrit de write-up pour celle-ci, donc un petit peu de contexte s'impose : dans Defused, on nous donnait une image présentant un circuit dans lequel on retrouvait un microcontrôleur ARM (STM32F103C8T6).
Cet article explique bien comment configurer IDA pour reverse ce type de binaire : https://blog.3or.de/starting-embedded-reverse-engineering-freertos-libopencm3-on-stm32f103c8t6.html
Une fois le binaire chargé et IDA configuré, on se retrouve face à un code assez court avec 6 fonctions (ici j'en avais déjà renommé quelques unes).

sub_27C semble être le "main" du programme, que IDA décompile :
Étudions d'abord quelques des autres fonctions avant de s'attarder au main. La fonction sub_120 (renommée hex_to_dec) :
Celle-ci prend une chaîne a1 et va convertir les deux premiers caractères depuis l'hexadécimal... et ajouter 4. Par exemple, 7C deviendrait 128.
Ensuite, regardons le sub_160 (renommé hex_to_index) :
Cette fonction va aussi convertir deux caractères hexadécimaux en décimal, mais va ensuite chercher, à un certain endroit dans la mémoire, l'octet résultant, et retourner sa position.
Cette zone mémoire commence en 67096 = 0x10618, c'est-à -dire à l'offset réel 0x618 dans le binaire. On dump sur 256 octets :
Sans surprise, il s'agit d'une permutation de la liste des octets de 0 Ã 255. La fonction retourne donc la position de notre octet dans cette table.
Enfin, la fonction sub_204 (renommée ici subtilement aMoinsBMoins2) :
Après étude, celle-ci semble simplement renvoyer a - b - 2, où a et b sont les valeurs décimales associées aux arguments (toujours en hexa) a2 et a1.
Avec toutes ces informations en main, nous pouvions alors comprendre la routine de chiffrement du main. C'est un peu fastidieux donc je vais directement sauter à l'explication de l'algorithme :
On lit le plaintext sous forme de chaîne hexadécimale, deux caractères par deux
Soit m[i] le i-ème octet du plaintext, et c[i] son chiffré :
Si i mod 4 = 0, alors c[i] = m[i] + 4
Si i mod 4 = 1, alors c[i] est l'indice de m[i] dans la table de permutation
Si i mod 4 = 2, alors c[i] = m[i] xor 0xCC
Si i mod 4 = 3, alors c[i] = m[i] - c[i-3] - 2
Le texte chiffré est c sous forme de chaîne hexadécimale
Il ne reste plus qu'à coder un algo de déchiffrement.
Et le résultat :
Conclusion
Une épreuve plutôt sympathique même si analyser le code en statique est légèrement sale et fastidieux. C'est la première fois que je fais un challenge de ce genre (reverse du ARM microcontrôleur) et je suis content d'avoir fait first blood !
Je suis d'ailleurs étonné du nombre peu élevé de validations sur cette épreuve, que je n'ai pas trouvée spécialement plus difficile que son homologue Defused qui en a 3 fois plus.
Enjoy!
Last updated
Was this helpful?