Les binaires sont téléchargeables en suivant ce lien (500ko). Ce sont des binaires linux 32 bits standards. Les exams nécessitent de trouver le bon mot de passe, à la manière des keygenme classiques des challenges que l'on trouve sur internet.
1/ exam1 - cold start
Comme a dit le formateur, cet exercice n'est présent que pour vous éviter de finir à 0 points :-).
kevin@slack:~/binaries$ ./exam1
Usage: ./exam1 key
kevin@slack:~/binaries$ ./exam1 test
Bad key
kevin@slack:~/binaries$ strings exam1
(je coupe un peu, et on observe enfin)
øÿuô
è\þÿÿY[ÉÃ
Usage: %s key
r56GoinQ
Bad key
Good key
ÿÿÿÿ
ÿÿÿÿ
(snip snip snip encore un peu...)
mainUsage: ./exam1 key
kevin@slack:~/binaries$ ./exam1 test
Bad key
kevin@slack:~/binaries$ strings exam1
(je coupe un peu, et on observe enfin)
øÿuô
è\þÿÿY[ÉÃ
Usage: %s key
r56GoinQ
Bad key
Good key
ÿÿÿÿ
ÿÿÿÿ
(snip snip snip encore un peu...)
_init
kevin@slack:~/binaries$
Sans trop réfléchir on lit les strings et on tombe sur le Usage, puis une série de caractères qui ressemblent à une clé, et les deux messages "good key/bad key". Sans plus attendre:
kevin@slack:~/binaries$ ./exam1 r56GoinQ
Good key
kevin@slack:~/binaries$
Good key
kevin@slack:~/binaries$
[Une anecdote à ce sujet: j'ai fait un challenge ou la clé était 'printf'. Bien qu'elle soit sous les yeux, aussi clairement indiquée, on ne pense pas à l'essayer :) ]
2/ exam2 - les moteurs sont chauds
L'exam2 est basé sur le même principe sauf que lire le binaire avec strings ne donne aucune indication valable. Il faut trouver une autre solution.
2/A/ La solution rapide
Le programme ltrace permet de tracer l'appel aux librairies. Puisque l'on se doute qu'un strcmp est fait pour comparer la clé entrée au clavier de la clé valide on regarde:
kevin@slack:~/binaries$ ltrace ./exam2 toto
__libc_start_main(0x80484a4, 2, 0xbf88a804, 0x8048590, 0x8048580
strcmp("AFc6mcw", "toto") = -51
puts("Bad key"Bad key
) = 8
+++ exited (status 0) +++
kevin@slack:~/binaries$
La solution crève les yeux.__libc_start_main(0x80484a4, 2, 0xbf88a804, 0x8048590, 0x8048580
strcmp("AFc6mcw", "toto") = -51
puts("Bad key"Bad key
) = 8
+++ exited (status 0) +++
kevin@slack:~/binaries$
kevin@slack:~/binaries$ ./exam2 AFc6mcw
Good key
kevin@slack:~/binaries$
Good key
kevin@slack:~/binaries$
2/B/ La solution du programmeur
Il existe une variable d'environnement LD_PRELOAD qui permet de surcharger l'appel des bibliothèques. Il suffit donc d'utiliser une bibliothèque qui détourne l'usage de strcmp pour en connaître ses arguments. Un man strcmp permet de connaître la structure de la fonction pour reprendre les mêmes arguments.
kevin@slack:~/binaries$ cat hijack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcmp(const char *s1, const char *s2)
{
printf(" String 1 = %s\n String 2 = %s\n ", s1, s2) ;
}
kevin@slack:~/binaries$ gcc -shared hijack.c -o hijack.so
kevin@slack:~/binaries$ LD_PRELOAD=$(pwd)/hijack.so ./exam2 toto
String 1 = AFc6mcw
String 2 = toto
Bad key
kevin@slack:~/binaries$
La solution est bien évidemment identique. WIN.#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcmp(const char *s1, const char *s2)
{
printf(" String 1 = %s\n String 2 = %s\n ", s1, s2) ;
}
kevin@slack:~/binaries$ gcc -shared hijack.c -o hijack.so
kevin@slack:~/binaries$ LD_PRELOAD=$(pwd)/hijack.so ./exam2 toto
String 1 = AFc6mcw
String 2 = toto
Bad key
kevin@slack:~/binaries$
3/ exam3 - on met les mains dans le cambouis
l'exam3 va obliger à regarder de l'assembleur dixit le formateur. On sort donc gdb, et l'analyse fastidieuse commence. Nous avons droit à une mini formation de la gui de metasm qui permet de résoudre très vite cet exercice. Pour cela on télécharge metasm à l'aide de hg
kevin@slack:~$ hg clone https://code.google.com/p/metasm
(... snip)
kevin@slack:~$ cd metasm
kevin@slack:~/metasm$ export RUBYDIR=/home/kevin/metasm/kevin@slack:~/metasm$ ruby samples/disassemble-gui.rb
On charge alors le fichier exam3 (menu file Open), on le désassemble à l'aide de la touche 'c', puis on appuye sur espace pour obtenir le graphe de fonctions, puis menu Actions->List fonctions, et on choisit le Main du programme. On obtient cela (cliquer sur l'image pour la voir en grand):
La lecture du binaire est plus aisée. Le premier bloc doit compter le nombre d'arguments. Le second bloc à gauche fait un strlen et si le résultat diffère de 9 part à la fonction loose (avec un nom pareil on se doute qu'il ne faut pas aller là-bas :) ), on sait donc déjà que le mot de passe doit faire 9 caractères première information.
Ensuite, on peut zoomer à l'aide de CTRL molette souris, et en vue d'avion on observe cela:
(oui les cadres sont blanc, je n'ai pas de police à la bonne taille apparemment).
On se doute donc immédiatement que le programme va comparer caractère après caractère la clé entrée par l'utilisateur.
Suivons donc les blocs pas à pas:
cmp al, 41h.
cmp signifie comparer. En code hexa, 41 est le 'A'. Nous savons donc que le A est le premier des 9 caractères du mot de passe. Le bloc suivant est beaucoup moins clair, c'est sans doute lié à une optimisation compilateur (?)
On va finalement sortir gdb. Tout d'abord, pour connaître l'adresse de ce cmp, on clique dessus, puis on presse la barre espace, ce qui nous amène à:
où l'on lit donc l'adresse: 0x08048521.
Nous allons donc placer un breakpoint à cette adresse, et étudier les registres edx et eax à ce moment là:
kevin@slack:~/binaries$ gdb exam3
(snip)
(snip)
(gdb) b *0x08048521
Breakpoint 1 at 0x8048521
(gdb) run Aaaaaaaaa
Starting program: /home/kevin/binaries/exam3 Aaaaaaaaa
Breakpoint 1, 0x08048521 in main ()
(gdb) info registers
eax 0x44 68
ecx 0x4c504300 1280328448
edx 0x61 97
ebx 0xb7fc2ff4 -1208209420
esp 0xbffff0e0 0xbffff0e0
ebp 0xbffff0f8 0xbffff0f8
esi 0x0 0
edi 0x0 0
eip 0x8048521 0x8048521
eflags 0x206 [ PF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)
Nous devons lancer le programme avec une clé de 9 caractères débutant par un A majuscule sinon nous sortirons avant. Une fois breakpointé, nous consultons les registres: edx vaut 0x61, ce qui correspond au a minuscule. eax vaut 0x44 qui est le D majuscule. Le deuxième caractère du mot de passe est donc le D majuscule.Breakpoint 1 at 0x8048521
(gdb) run Aaaaaaaaa
Starting program: /home/kevin/binaries/exam3 Aaaaaaaaa
Breakpoint 1, 0x08048521 in main ()
(gdb) info registers
eax 0x44 68
ecx 0x4c504300 1280328448
edx 0x61 97
ebx 0xb7fc2ff4 -1208209420
esp 0xbffff0e0 0xbffff0e0
ebp 0xbffff0f8 0xbffff0f8
esi 0x0 0
edi 0x0 0
eip 0x8048521 0x8048521
eflags 0x206 [ PF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)
En progressant de la même manière, il est possible de retrouver les 8 premiers caractères de la clé. huit? que 8? Or nous savons qu'il en faut neuf!
Petite blague du formateur, il ne faut pas chercher un 9e caractère ou une instruction oubliée. En effet, ce programme ne vérifie que les 8 premiers caractères d'une clé qui en contient 9. Ce qui signifie que n'importe quelle caractère en 9 position est valide!
kevin@slack:~/binaries$ ./exam3 AD13=xhca
Good key
kevin@slack:~/binaries$ ./exam3 AD13=xhcb
Good key
kevin@slack:~/binaries$ ./exam3 AD13=xhc9
Good key
kevin@slack:~/binaries$
Good key
kevin@slack:~/binaries$ ./exam3 AD13=xhcb
Good key
kevin@slack:~/binaries$ ./exam3 AD13=xhc9
Good key
kevin@slack:~/binaries$
[info pratique: sous linux man ascii affiche le code ascii des caractères]
4/ exam4 - sortie de piste!!
Pour cet exercice, je pense que toute la salle s'est fait berner. On est chaud, on a le gdb dégainé, le metasm-gui ouvert, donc on regarde direct le programme. Sauf que là, on a deux surprises:
Tout d'abord un graphe pas très engageant, et ensuite une absence totale de fonction main...
La solution est à portée de main. Le programme est en fait packé, il faut le dépacker pour pouvoir l'analyser. Un simple hexdump donne une première idée, un strings confirme:
kevin@slack:~/binaries$ hexdump -C exam4 | head
00000000 7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 03 00 01 00 00 00 e0 dd c3 00 34 00 00 00 |........àÝÃ.4...|
00000020 00 00 00 00 00 00 00 00 34 00 20 00 02 00 28 00 |........4. ...(.|
00000030 00 00 00 00 01 00 00 00 00 00 00 00 00 10 c0 00 |..............À.|
00000040 00 10 c0 00 e0 d5 03 00 e0 d5 03 00 05 00 00 00 |..À.àÕ..àÕ......|
00000050 00 10 00 00 01 00 00 00 94 02 00 00 94 82 0c 08 |................|
00000060 94 82 0c 08 00 00 00 00 00 00 00 00 06 00 00 00 |................|
00000070 00 10 00 00 5f ac 1b b0 55 50 58 21 ff 07 0d 0c |...._¬.°UPX!ÿ...|
00000080 00 00 00 00 2f d2 08 00 2f d2 08 00 f4 00 00 00 |..../Ò../Ò..ô...|
00000090 80 00 00 00 08 00 00 00 77 1f a4 f9 7f 45 4c 46 |........w.¤ù.ELF|
kevin@slack:~/binaries$ strings exam4 | grep UPX
°UPX!ÿ
UPX!
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.07 Copyright (C) 1996-2010 the UPX Team. All Rights Reserved. $
ùUPX!u
UPX!
kevin@slack:~/binaries$
Une fois dépacké avec un coup de upx -d, le programme est quasiment celui de l'exam3.00000000 7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 03 00 01 00 00 00 e0 dd c3 00 34 00 00 00 |........àÝÃ.4...|
00000020 00 00 00 00 00 00 00 00 34 00 20 00 02 00 28 00 |........4. ...(.|
00000030 00 00 00 00 01 00 00 00 00 00 00 00 00 10 c0 00 |..............À.|
00000040 00 10 c0 00 e0 d5 03 00 e0 d5 03 00 05 00 00 00 |..À.àÕ..àÕ......|
00000050 00 10 00 00 01 00 00 00 94 02 00 00 94 82 0c 08 |................|
00000060 94 82 0c 08 00 00 00 00 00 00 00 00 06 00 00 00 |................|
00000070 00 10 00 00 5f ac 1b b0 55 50 58 21 ff 07 0d 0c |...._¬.°UPX!ÿ...|
00000080 00 00 00 00 2f d2 08 00 2f d2 08 00 f4 00 00 00 |..../Ò../Ò..ô...|
00000090 80 00 00 00 08 00 00 00 77 1f a4 f9 7f 45 4c 46 |........w.¤ù.ELF|
kevin@slack:~/binaries$ strings exam4 | grep UPX
°UPX!ÿ
UPX!
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.07 Copyright (C) 1996-2010 the UPX Team. All Rights Reserved. $
ùUPX!u
UPX!
kevin@slack:~/binaries$
5/ exam5 - explosion de moteur
Je n'ai pas fait cet exam, ni même tenté de le résoudre. Il fait crasher gdb, il fait planter metasm-gui, et selon le formateur seul edb debugger réussit à l'ouvrir après un temps très long. Peut-être un post de blog dans le futur :-)
Une explication de simple1 est à venir, étant un peu différent de ces keygenme.
Hello,
RépondreSupprimerPour ma part, j'arrive a ouvrir exam5 sans probleme avec metasm...
$ ruby samples/disassemble-gui.rb --fast exam5 0x8048170 # le point d'entree
Le desassemblage prend moins de 20 secondes sur mon PC.
Ca a l'air sympa comme atelier :)
RépondreSupprimerFaudra que je me plonge dans MetaASM ça me changera de HT Editor
@Anonyme: une fois ouvert, essayes de naviguer dedans, ça rame en boucle sans jamais finir.
RépondreSupprimerSi tu as ouvert la gui depuis un xterm, tu verras que dans celui-ci il y a des bordées successives de recherches sans fin. Ensuite, tu as peut-être un PC surpuissant :) ou c'est le switch --fast qui aide.
@devloop: L'atelier était très bien, oui. metasm aussi d'ailleurs. Par contre, la seule doc que j'ai trouvé est contenue dans les premières lignes du programe :-/
Avec --fast, ca marche sans probleme (l'option desactive le moteur de backtracking, qui est gourmand en ressources). On peut naviguer fluidement, meme sur un PC modeste.
RépondreSupprimer@Anonyme: pas concluant chez moi même avec le --fast :-(
RépondreSupprimerJe charge le binaire, touche 'c', puis espace. Ca rame quelques minutes puis ça m'affiche le graphe, jusque là tout va bien.
Mais quoi que je fasse ensuite (list function) ou cliquer sur une valeur et appuyer sur Entrée me freeze l'interface.
Et pourtant j'ai un dual core et 4Go de RAM.