Principe:
Retrouver un mot de passe (en explorant les registres et la stack d'un interpréteur de 'VM')
Le challenge
Le zip a été ici réduit à son strict minimum. L'ensemble des fichiers est disponible à cette addresse , incluant la partie glibc (que j'aurai pu simplifier, mais tant pis)
Lancement
Evidemment, le mot de passe n'est pas aisément trouvable directement dans la source de vm_data.bin, mais cela vaut le coup d'y jeter un oeil, pour essayer de repérer des patterns, des strings, etc
Données vs instructions
L'idée était ici de modifier tous les octets: si la VM plante, c'est que l'octet fait partie des instructions (ou des données "critiques", comme une longueur de buffer). Si la VM ne plante pas, c'est que l'octet fait partie des données simples, par exemple, les caractères d'un message affiché ("Pass?") ou les caractères du mot de passe
Un tour dans le débugger
Comme l'altération des octets de vm_data ne m'a pas mené loin, je suis parti chercher les sources de glibc, pour le compiler et lancer la VM sans devoir réutiliser les scripts de Fourchette
On pouvait utiliser la libc fournie par le challenge, mais je me suis dit que j'aurai peut-être besoin de hooker quelques fonctions pour faciliter le taff, donc, je suis parti sur la recompilation. Dans ce cas, pwninit ou bien glibc all-in-one + patchelf peuvent être utilisés
Notez que je suis maintenant dans ~/ctf: en effet, la libc a eu quelques soucis avec le chemin que j'utilise habituellement, probablement à cause des espaces et des parenthèses. Je vous recommande donc de faire de même
N'ayant pas trouvé grand chose d'utile ainsi, je passe rapidement
Notez que certains octets pourraient être altérables car ils ne sont jamais "exécutés" (parce qu'un JUMP les as évités ou autre)
Le nombre d'instructions
L'idée suivant était de prendre GDB (plutôt qu'edb car GDB est scriptable), de lancer la VM, d'entrer un mot de passe, et de compter le nombre d'instructions jusqu'à la fin du programme. Avec de la chance, le nombre d'instruction va varier en fonction de l'entrée, révélant peut-etre le mot de passe lettre par lettre, ou au moins, sa longueur
Il faut en pratique utiliser si, car ni va exécuter les call comme une seule instruction, là où si n'exécutera qu'une seule instruction machine ("step into", en gros)
A ce stade, on sait que la comparaison entre l'entrée et le mot de passe ne se fait donc pas lettre à lettre directement. Une possibilité serait que la longueur du mot de passe soit d'abord comparée à l'entrée, et qu'ensuite leurs contenus soient comparés
Longueur du mot de passe
On peut donc partir de l'hypothèse qu'il faut 24 caractères pour le mot de passe, ce qui ne sera pas facilement brute-forçable, sauf à être lettre-par-lettre
Reverse? pour de vrai?
Tracing
XOR
En pratique, je ne m'attends pas à trouver le mot de passe directement dans un registre, mais je compte trouver ce que j'ai entré comme mot de passe dans les registres, et une transformation/chiffrement de cette entrée avant d'être comparée au mot de passe stocké dans le vm_data
On voit ici que 8 caractère de mon entrée sont dans un registre: comme on l'avait anticipé lors de la recherche de la longueur du mot de passe, la VM marche en 64 bits (en blocs de 8 octets)
Test du premier bloc
On a alors réussit à "déjouer" 2 des 4 blocs contenant un jump 0fca0404: la longueur du mot de passe et la valeur du premier bloc de 8 caractères de ce mot de passe. Les deux autres testent sans doute les deux autres morceaux du mot de passe (qui fait 3 x 8octets)
Encore du XOR
Notez qu'on trouvera des instructions du type Rx XOR Ry avec Rx et Ry, identiques. Cela permet en fait de mettre la valeur d'un registre à 0, et ce n'est donc pas en lien avec ce qu'on recherche.
Cette valeur est intrigante car elle apparait alors qu'on retrouve le cbe7a5e2decbe7bd précent dans l'autre registre
En pratique, j'ai mis 5 bonnes minutes à tilter que le début du mot de passe étant Is_Th1s_, soit "is this", la fin du mot de passe pourrait bien être un point d'interrogation… ou plusieurs! donc _??!!??? est une fin de mot de passe crédible!
On a donc déjoué 3 des 4 blocs de test: la longueur, le XOR du premier bloc, le XOR du dernier bloc, et il ne nous manque plus que le bloc central de 64 bits
Dernier bloc
Un brute force?
Un autre XOR?
J'ai retrouvé, dans ces XORs, les morceaux Is_Th1s_ et _??!!??? d'ailleurs, ce qui m'aurait permis de flagguer plus vite peut-être