PROJET AUTOBLOG


Tiger-222

Archivé

Site original : Tiger-222

⇐ retour index

ELF - Random Crackme

mardi 9 avril 2013 à 15:10
Le challenge consiste à donner le bon mot de passe. Le fichier ch5.zip est fourni.

Étape 1


Décompresser l'archive... Facile !
On se retrouve avec un fichier nommé crackme_wtf.


Étape 2


MàJ : il suffit de faire un "ar -x crackme_wtf" pour décompresser le fichier.
Tu peux sauter cette étape.


Sous Debian GNU/Linux, ce fichier a l'icône d'une archive, cependant, pas moyen d'en faire quelques chose.
La commande file renvoie :
$ file crackme_wtf
crackme_wtf: current ar archive
Bon, voyons à l'aide d'un éditeur héxadécimal ce que donnent les 8 premiers octets :
$ hexdump -n 8 -C crackme_wtf
00000000 21 3c 61 72 63 68 3e 0a |!<arch>.|
Mouai... À tout hasard, l'excellent hachoir-subfile saura peut-être m'en dire plus.
(hachoir-subfile) L'idée est d'extraire des fichiers (non compressés, non chiffrés et non fragmentés) contenus dans d'autres fichier – Victor STINNER.

$ hachoir-subfile crackme_wtf
[+] Start search on 14418 bytes (14.1 KB)
[+] File at 0: Unix archive
[+] File at 424: ELF Unix/BSD program/library: 32 bits
[+] End of search -- offset=14418 (14.1 KB)
Hop hop ! Que vois-je ? À l'offset 424 il y aurait un binaire ELF ? Ok, tail est notre ami :
$ tail --bytes=+425 crackme_wtf >Crackme
$ file Crackme
chal: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, not stripped
$ ldd Crackme
linux-gate.so.1 => (0xf7736000)
libc.so.6 => /lib32/libc.so.6 (0xf75b3000)
/lib/ld-linux.so.2 (0xf7737000)
$ chmod +x Crackme
$ ./Crackme
** Bienvenue dans ce challenge de cracking **
[+] Password :azerty
[!]Access Denied !
[-] Try again
L'exécutable est lié dynamiquement aux bibliothèques, ce qui sera intéressant par la suite.


Étape 3


Nous avons enfin l'exécutable, voyons ce qu'on peut en faire.
$ strings Crackme
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
exit
sprintf
srand
puts
time
__stack_chk_fail
stdin
getpid
fgets
strlen
memset
getchar
__errno_location
fputc
malloc
stderr
ptrace
fwrite
strchr
strcmp
__libc_start_main
free
GLIBC_2.4
GLIBC_2.0
PTRh
VTEP
IQAV
Y[_]
[^_]
_VQLGE_TQPTYD_KJTIV_
%lld%s
[-] Allocation memoire echouee!
[-]Debugger detecte ... Exit
** Bienvenue dans ce challenge de cracking **
[+] Password :
[!]Access Denied !
[-] Try again
[+]Good password
[+] Clee de validation du crack-me :
%d_%s%d_
Il y a une protection anti-debugger apparemment et quelques appels à des fonctions qui peuvent être intéressantes telles que strcmp, strlen ou même strchr.

Je tente quand même d'ouvrir le binaire dans un débugger :
$ gdb Crackme            
# (...)
Reading symbols from /home/tiger-222/chal...done.
(gdb) run
Starting program: /home/tiger-222/chal
[-]Debugger detecte ... Exit
[Inferior 1 (process 6523) exited with code 01]
(gdb) quit

$ strace ./Crackme
(...)
write(2, "[-]Debugger detecte ... Exit\n", 29[-]Debugger detecte ... Exit
(...)
Comme il fallait s'y attendre, gdb et strace ne fonctionnent pas. J'opte pour l'usurpation (hook) de la fonction strcmp.


Étape 4

Alors, l'usurpation, comment ça se passe ?
Et bien il y a une variable d'environnement sous le doux nom de LD_PRELOAD qui sert à charger ses propres bibliothèques de fonction. Je vais m'en servir pour dire au programme de prendre la mienne plutôt que celle du système.

Voici le code pour hook_strcmp.c :
#define _GNU_SOURCE
#include <stdio.h> #include <dlfcn.h>

int strcmp(const char *str1, const char *str2) {
printf("[Hook strcmp] str1 = %s\n", str1);
printf(" str2 = %s\n", str2);

// Appel de la véritable fonction
typeof(strcmp)* function;
function = dlsym(RTLD_NEXT, "strcmp");
return (*function)(str1, str2);
}
Que l'on compile tel que :
$ gcc -Wall -fPIC -c -o hook_strcmp.o hook_strcmp.c
hook_strcmp.c:5:5: warning: conflicting types for built-in function ‘strcmp’ [enabled by default]
$ gcc -shared -fPIC -Wl,-soname -Wl,hook_strcmp.so -ldl -o /tmp/hook_strcmp.so hook_strcmp.o
L'erreur, c'est normal, le compilo nous informe officiellement que notre fonction est en conflit avec celle du système, tiens donc !
Pour trouver le prototype d'une fonction, va faire un tour sur ce site.

Nous avons donc notre bibliothèque perso, voyons ce que ça donne :
$ export LD_PRELOAD="/tmp/hook_strcmp.so"
$ ./Crackme

** Bienvenue dans ce challenge de cracking **

[+] Password :azerty
[Hook strcmp] str1 = azerty
str2 = 235625580_VQLGE_TQPTYD_KJTIV_

[!]Access Denied !
[-] Try again
Ah ! C'est un début prometteur !

Testons str2 :
$ ./Crackme

** Bienvenue dans ce challenge de cracking **

[+] Password :235625580_VQLGE_TQPTYD_KJTIV_
[Hook strcmp] str1 = 235625580_VQLGE_TQPTYD_KJTIV_
str2 = 139734408_VQLGE_TQPTYD_KJTIV_

[!]Access Denied !
[-] Try again
Maintenant c'est clair, le mot de passe est constitué d'un nombre qui semble aléatoire suivi de la chaîne _VQLGE_TQPTYD_KJTIV_.

Tout à l'heure, la commande strings nous a renvoyé d'autres noms de fonctions utilses pour le pseudo-aléatoire tel que srand, rand et time. Notons aussi getpid(), il arrive que le pid soit ajouté comme sel.

C'est parti pour de l'usurpation de bourin, hook_multi.c :
#define _GNU_SOURCE
#include <stdio.h> #include <dlfcn.h>

int strcmp(const char *str1, const char *str2) {
printf("[Hook strcmp] str1 = %s\n", str1);
printf(" str2 = %s\n", str2);

// Appel de la véritable fonction
typeof(strcmp)* function;
function = dlsym(RTLD_NEXT, "strcmp");
return (*function)(str1, str2);
}

int getpid() { printf("[Hook getpid] 0\n"); return 0; }
int srand() { printf("[Hook srand] 0\n"); return 0; }
int time() { printf("[Hook time] 0\n"); return 0; }
Tout le monde renverra 0, comme ça pas de chichi, si le programme souhaite un nombre pseudo-aléatoire entre 0 et 0, ça restreint les possibilités !

Testons :
$ gcc -Wall -fPIC -c -o hook_multi.o hook_multi.c
hook_strcmp.c:5:5: warning: conflicting types for built-in function ‘strcmp’ [enabled by default]
$ gcc -shared -fPIC -Wl,-soname -Wl,hook_multi.so -ldl -o /tmp/hook_multi.so hook_multi.o
$ export LD_PRELOAD="/tmp/hook_multi.so"
$ ./Crackme
[Hook time] 0
[Hook srand] 0
[Hook getpid] 0
[Hook srand] 0
[-]Debugger detecte ... Exit
Arf ! Pas bon ça !
Les usurpations de time, srand et getpid semblent fonctionner, je supprime celle de rand... Ça fonctionne. Vilain petit canard !

Résultat :
$ export LD_PRELOAD="/tmp/hook_multi.so"
$ ./Crackme
[Hook time] 0
[Hook srand] 0
[Hook getpid] 0

** Bienvenue dans ce challenge de cracking **

[+] Password :azerty
[Hook strcmp] str1 = azerty
str2 = 0_VQLGE_TQPTYD_KJTIV_

[!]Access Denied !
[-] Try again

Je réessaie 3-4 fois et str2 vaut toujours la même chose, je l'entre comme mot de passe et.. TADAAA !!
$ ./Crackme
[Hook time] 0
[Hook srand] 0
[Hook getpid] 0

** Bienvenue dans ce challenge de cracking **

[+] Password :0_VQLGE_TQPTYD_KJTIV_
[Hook strcmp] str1 = 0_VQLGE_TQPTYD_KJTIV_
str2 = 0_VQLGE_TQPTYD_KJTIV_

[+]Good password
[+] Clee de validation du crack-me : *****
Bon je cache quand même le mot de passe pour ne pas te mâcher tout le travail.

Je me suis inspiré de cette source.