Crackage de calculatrice et stéganographie

Write-up du challenge Préchall du CTF FCSC (édition 2022)

Le

Bonjour à tous :), juste après le hackday vient maintenant le FCSC, CTF individuel cette fois. Je commence avec un write-up portant sur le challenge de teasing, qui mêle stéganographie et cracking. Trêve de blabla, c'est parti !

Sommaire

  • Partie 1 : Stéganographie
  • Partie 2 : Reverse engineering du programme pour calculatrice

Partie 1: Stéganographie

Après un petit coup sur https://aperisolve.fr/, on s'aperçoit qu'il y a des dinosaures cachés dans l'image.

Aperi'Solve : l'analyse des plans de bits révèle des silhouettes de dinosaures cachées dans l'image du challenge

Après pas mal de recherche google, je tombe sur

Alphabet Ding-o-saurs : tableau associant chaque lettre de A à Z à une silhouette de dinosaure

Les caractères correspondent à ceux sur l'image, seulement il en manque quelques-uns. Je cherche alphabet Ding-o-saurs sur google, et je tombe sur le site dafont qui m'apprend que c'est une police d'écriture ! (que j'installe d'ailleurs).

Je recopie chaque caractère dans word avec la police ding-o-saurs.

Word : les dinosaures retranscrits avec la police Ding-o-saurs donnent un texte encore chiffré ressemblant à une URL

Je m'aperçois qu'il y a encore un chiffrement. Par réflexe, Je m'empresse de tester s'il ne s'agit pas d'un chiffrement par décalage, mais il s'agit d'autre chose. On remarque le :// qui semble correspondre avec un site web. De plus, le nombre de caractères entre les tirets correspond avec l'url du site web du FCSC: https://france-cybersecurity-challenge.fr. On se base sur ça pour construire un alphabet, et on décode:

text = """
WKSMGMGHIMOQOYJOPSIIOKVSPKODLOKOOUSPO
JOZOZCSVVOQBOMGHIUKGHMOKOYVSNLQSZOUUO
SJKOIIOCUUPI ://NKSQZO-ZTWOKIOZHKLUT-
ZCSVVOQBO.NK/WPWZDKPVNBYDYUBBBPWZ
"""
text = text.replace("C","h").replace("U","t").replace("P","p").replace("I","s").replace("N","f").replace("K","r").replace("S","a").replace("Q","n").replace("Z","c").replace("O","e")
text = text.replace("V","l").replace("B","g").replace("T","y").replace("W","b").replace("H","u").replace("L","i").replace("M","v").replace("G","o").replace("D","m").replace("Y","z")
text = text.replace("J","d")
print(text)

Ce qui nous affiche:

bravo vous venez de passer la premiere etape de ce challenge vous trouverez la fina cette
adresse https://france-cybersecurity-challenge.fr/bpbcmrplfgzmztgggpbc

Navigateur : la page cachée du FCSC 2022 fournit le programme fcsc.8xp pour l'étape suivante, avec un mème de chat


Partie 2: Reverse engineering du programme pour calculatrice

1. Prise d'informations

On ouvre directement le fichier dans Hxd, à la recherche d'informations pertinentes.

HxD : chaînes du fichier révélant un crackme TI-83+ qui attend une entrée de 32 caractères

Humm, il semblerait qu'il s'agit d'un programme se lançant sur calculatrice Texas Instrument, et plus précisément sur le modèle TI-83. On note également la taille du password: 32 caractères. En googlant un peu, on tombe sur un write-up qui nous indique l'outil dont on va se servir: "TilEm Debugger". On télécharge également la ROM fourni dans le write-up. On lance TilEm, puis clique droit, open calculator, et on y balance la ROM. Puis clique droit, send, fcsc.8xp.

On lance notre programme en réalisant l'opération Asm(prmFCSC). ( 2nd > 0 pour ouvrir le catalogue, puis on sélectionne Asm, et PRGM > prmFCSC).

Émulateur TilEm : la TI-83 Plus affiche le message de bienvenue du crackme du FCSC

Pour ma part, j'ai d'abord essayé de trouvé le flag en statique, avec la version pro d'IDA. On commence par cherché le modèle de processeur utilisé dans les TI-83.

Wikipédia : fiche technique de la TI-83 indiquant un microprocesseur Zilog Z80

Il s'agit d'un processeur zilog z80. On trouve de la documentation sur le jeu d'instruction assembleur ici, et sur les registres du processeurs ici.

2. Analyse statique

On lance IDA pro, on ouvre notre fichier et on sélectionne le processeur zilog z80. On laisse les paramètres par défaut, et on commence notre étude statique.

IDA : succession de blocs Z80 qui xorent une valeur puis la comparent à l'entrée pointée par IX

On remarque tout de suite cette succession de xor. On prend soin de noté chaque valeur, et surprise, il y en a 32, comme la taille de la clé ! (mais si rappelez-vous).

[0xc2,9,0x0d,0x0a,7,0xc,9,0x10,0x14,7,6,0xe,0xa,0xf,0xb,0xa,0xa,1,8,0xc,0xa,8,7,0xe,0x1a,0x1c,7,0xb,0x10,0x1F,2,3]

J'ai ensuite cherché une autre chaine de 32 caractères, le flag xoré avec la clé, mais sans succès. Je suis donc parti à la recherche du flag en me lançant dans une étude dynamique, cette fois.

3. Analyse dynamique

Bon, là ça a été un peu laborieux. J'ai pas mal pataugé dans le debugger, car on y trouve le code assembleur de toute l'exécution de la calculatrice (Ca inclut l'affiche des caractères). Pour me repérer, j'ai cherché assembleur le code trouvé précédemment dans IDA, qu'on trouve au niveau des adresses 0X419DXX.

On pose des breakpoints dans cette zone, et on observe des choses très intéressantes, en modifiant la valeur du registre PC (qui contient l'adresse de la prochaine instruction à exécuter).

TilEm Debugger : en forçant le registre PC, la calculatrice affiche le message de victoire avec un flag factice

On détermine alors les choses suivantes:

Adresse Instruction Action
0x419D9E call getkey Attends une entrée de l'utilisateur après l'affichage du message de bienvenue
0x419DA1 call ClrLCDFULL Efface l'écran
0x419DAA cp $20 Vérifie que la taille de l'input est bien de 32 caractères
0x419DB8 call 0x419FC5 Affiche "perdu..."
0x419DBD call 0x419F87 Affiche "gagné, le flag est"
0X419DAE call 0x419F65 Lance une série d'instruction qui vérifie que l'input est bien le flag

On cherche ensuite notre input dans la zone de mémoire que l'on trouve à l'adresse 0x41A0A2. On comprends comment sont codé les caractères: de 0x8e à 0x97, les nombres 0,1,2,3,4,5,6,7,8,9 et de 0x9A à 0x9F les lettres A,B,C,D,E,F. Par exemple, si j'envoie 32 fois 7 dans l'input, on obtient 32 fois 95.

TilEm Debugger : en mémoire, une saisie de 32 fois le chiffre 7 apparaît sous forme de 32 octets 0x95

Passons maintenant à la fonction xor déjà étudié précédemment.

TilEm Debugger : instructions XOR puis CP (IX) où l'on lit le registre A attendu pour chaque caractère

Pour résumer ce que fait la fonction: elle load une valeur dans le registre A. Elle xor le registre A, puis elle compare cette valeur avec celle se trouvant à IX, qui s'avère être notre input. Si les 2 valeurs s'avèrent être les mêmes, ça affiche un 1 sur l'écran, puis ça passe au caractère suivant en incrémentant IX de 1. Si ce n'est pas le cas, ça n'affiche pas le 1 sur l'écran, mais ça enchaine quand même aux caractères suivants. On comprend alors que notre objectif est que l'input soit égal à la valeur du registre A après le xor. En posant un break à chaque CP (IX) et en notant chaque valeur de A, on obtient:

flag = [0x92,0x9b,0x96,0x9c,0x9b,0x97,0x9e,0x8e,0x9a,0x9d,0x9b,0x95,0x9f,0x90,0x9b,0x91, 0x9b,0x9a,0x92,0x9e,0x94,0x9c,0x9b,0x95,0x8f,0x93,0x94,0x9f,0x8f,0x90,0x92,0x91]

Il ne reste plus qu'à transformer chaque valeur hexadécimal en caractère.

flag = [0x92,0x9b,0x96,0x9c,0x9b,0x97,0x9e,0x8e,0x9a,0x9d,0x9b,0x95,0x9f,0x90,0x9b,0x91,
     0x9b,0x9a,0x92,0x9e,0x94,0x9c,0x9b,0x95,0x8f,0x93,0x94,0x9f,0x8f,0x90,0x92,0x91]
decrypt_flag = ""

for i in flag:
    if i >= 0x9a:
        decrypt_flag += hex(i)[-1]
    else:
        decrypt_flag += chr(i-0x5e) 
print(decrypt_flag)
'''
FCSC{4b8cb9e0adb7f2b3ba4e6cb7156f1243}
'''

Voilà pour la première épreuve de ce FCSC 2022. L'aventure continue !

fcsc.8xp , TI-testrom.rom

Accès Restreint

Cet article n'est pas (encore) publique.
Pour obtenir un accès anticipé, contactez-moi.

[[ passwordError ]]

[[ post.title ]]

[[ post.description ]]

Le [[ post.date ]]

[[ tag ]]
[[ currentMatchIndex + 1 ]] / [[ searchMatches.length ]] 0 / 0

Sommaire

Page principale