UfoCTF 2013 | LockUpMe [Write Up]

Dans cette mission nous était donné un exécutable Windows, avec une combinaison de 9 chiffres à retrouver.

int

Passons tout d’abord le binaire sous PEiD afin de détecter d’éventuelles protections.

peid

Le crackme est packé UPX. On l’unpack de manière très classique : on load le binaire sous OllyDBG, puis on place un breakpoint sur le JMP de fin qui pointe vers l’OEP :

olly1

On presse F9 pour lancer le programme et l’arrêter au breakpoint : ainsi, l’unpacking, en mémoire, a été fait. En faisant un F8, on tombe sur le programme original. Le point d’entrée d’origine se situe donc en 0040A138. On dump le processus avec OllyDump (sans Rebuild Import). On lance le binaire packé, puis on ouvre ImportREC, et on y attache son processus. On rentre l’OEP : A138, on clique sur « IAT AutoSearch », « Get Imports », puis « Fix Dump », où on sélectionne le dump précédemment effectué avec OllyDump. Voilà, notre crackme est unpack !

Commençons maintenant l’épreuve. Le crackme utilise en fait une animation Flash pour l’interface (séléction de la combinaison, son, etc.). C’est ensuite le programme qui gère la vérification de cette combinaison de 9 chiffres.

En avançant un tout petit peu avec quelques F8 et en regardant ensuite dans les différents calls (Search for -> All Intermodular Calls), quelques fonctions nous interpellent, comme isalpha ou strchr. On pose un breakpoint en 04072A9 et on démarre le programme. On rentre une combinaison du style 123456789. Le programme s’arrête bien à l’endroit souhaité :

olly2

Dans les registres, on peut apercevoir quelque chose d’assez intéressant.

olly3

Allons en apprendre un peu plus sur cette chaine de caractères, en faisant un clic droit sur 004E5341, puis « Follow in Dump ».

olly4

Tiens, du XML avec 9 nombres! Ceux-ci sont sûrement issus du SWF : ces nombres seraient donc ce que nous avons entré. On peut donc établir la correspondance suivante :

123456789
969196434

On relance le programme, et on fait des tests sur plusieurs entrées. On peut établir plusieurs correspondances :

000000000
406728315

111111111
517839426

Tiens : avec des 1, le nombre correpond au même qu’avec celui des 0, mais avec +1 à chaque chiffre.

000000001
406728316

En modifiant le dernier digit, c’est bien le dernier digit qui est modifié aussi.

100000000
406728415

Ah, cette fois-ci c’est pas le premier chiffre qui a changé (on se base sur « 406728315 » qui est le résultat de « 000000000 »), mais le 7ème chiffre.
On peut déjà, à partir de là, comprendre la logique de transformation : les digits sont permutés, puis on y ajoute, dans l’ordre, 4, 0, 6, 7, 2, 8, 3, 1 et 5.
En établissant les correspondances suivantes, on peut retrouver la permutation effectuée :

# Cas normal
000000000
406728315

# Le 7ème digit change
100000000
406728415

# Le 8ème digit change
010000000
406728325

# Le 3ème digit change
001000000
407728315

...

La permutation finale se trouve être 783412569.

En résumé : notre combinaison est permutée selon la permutation ci-dessus, puis à chaque digit, on ajoute 4, 0, 6, 7, 2, 8, 3, 1 et 5 (si on dépasse 9, on revient à 0 ; on travaille donc modulo 10).

Pour revenir en arrière, nous n’avons qu’à soustraire la clé, puis refaire la permutation. Mais jusqu’ici, nous n’avons encore aucune trace de comparaison ou quoi que ce soit : continuons donc l’analyse du programme à la recherche d’une comparaison.

En 0404190, on trouve une routine assez intéressante. Il faut la reconnaitre : c’est un calcul de hash MD5. Posons un breakpoint dessus, puis lançons le programme avec une combinaison bidon du style « 123456789 » (qui sera transformée en « 969196434 »). Le programme s’arrête juste avant le calcul du hash MD5. À moins que vous voulez vous taper tout le calcul, vous pouvez poser un second breakpoint juste après, aux alentours de 04048D3. On sort de la routine en avançant à coups de F8, puis on tombe vers une petite boucle en 00404B70 qui s’occupe de placer le MD5 en 0018F1AC. Après les 16 itérations de la boucle, le md5 calculé est (en héxadécimal) :

3504BF0AA09DA5294D6CE1F0294A6A0D

…ce qui correspond bien au hash MD5 de « 969196434 ».

Un peu plus loin, en 004022C2, se situe une boucle un peu étrange (qui compte de 0x1337 à 0x1347… ce qui fait bien 16 octets) qui s’occupe de comparer le md5 calculé avec un autre md5 dans la mémoire, en 00410378 :

AE7AA70CDABAAB3B76B9694B51A92732

Le bruteforce de ce hash serait un peu long (10 ^ 9 possibilités). Heureusement, des sites comme md5decrypter.co.uk nous donne le plaintext de ce hash assez vite :

279451446

Il ne reste plus qu’à appliquer la transformation inverse sur ce nombre.

Tout d’abord, on soustrait la clé (406728315) sur du modulo 10, ce qui donne :

n = "279451446"
k = "406728315"
p = ''
for i in range(9):
	p += str((int(n[i]) - int(k[i])) % 10)
print p

 

873733131

On applique maintenant la permutation 783412569, qui donne la combinaison finale :

133787331

Wooot! On valide avec 133787331.
Enjoy.

woot

Laisser un commentaire