Executable : https://repo.zenk-security.com/hackingweek2014_ctf/crackme-03
$ file crackme-03 crackme-03: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.32, dynamically linked (uses shared libs), stripped
Le crackme 3 est un ELF 32 bits.
Dans celui-ci, la fonction principale se compose de plusieurs boucles de déchiffrement de code et d'un peu d'obfuscation.
LOAD:080484DA push offset aEnterPassword ; "Enter password:\n" LOAD:080484DF call printf_0 LOAD:080484E4 mov esp, ebp LOAD:080484E6 mov ebp, esp LOAD:080484E8 sub esp, 0Ch LOAD:080484EB and esp, 0FFFFFFF0h LOAD:080484EE add esp, 0Ch LOAD:080484F1 push 9 LOAD:080484F3 push offset mypasswd LOAD:080484F8 push 0 LOAD:080484FA call read_0 LOAD:080484FF mov esp, ebp LOAD:08048501 mov byte ptr [eax+8048488h], 0 LOAD:08048508 mov ecx, 0C46981Dh LOAD:0804850D mov esi, ds:dword_8049D32 LOAD:08048513 sub ecx, esi LOAD:08048515 mov ds:dword_8049D6E, ebp LOAD:0804851B sub ebp, 2EC33D4Eh LOAD:08048521 mov ebp, ds:dword_8049D6E LOAD:08048527 mov ds:dword_8049D6E, 180F301h LOAD:08048531 add ecx, ds:dword_8049E0A LOAD:08048537 mov edi, 7Dh LOAD:0804853C LOAD:0804853C loc_804853C: ; CODE XREF: LOAD:080485A9j LOAD:0804853C mov ebx, [ecx] LOAD:0804853E add ebx, 0A67D0AEEh LOAD:08048544 mov ds:dword_8049D58+2, esi LOAD:0804854A mov ds:dword_8049E56, esi LOAD:08048550 mov ds:dword_8049E56, 2868941h LOAD:0804855A mov esi, ds:dword_8049D58+2 LOAD:08048560 mov ds:dword_8049D58+2, 53020D9h LOAD:0804856A mov edx, 6A62559h LOAD:0804856F sub ebx, 0A67D0AEEh LOAD:08048575 sub ebx, 115C0CABh LOAD:0804857B mov ds:dword_8049DAE, esi LOAD:08048581 add esi, 0F34126C9h LOAD:08048587 mov esi, ds:dword_8049DAE LOAD:0804858D LOAD:0804858D loc_804858D: ; CODE XREF: LOAD:080485ABj LOAD:0804858D mov ds:dword_8049DAE, 3EDB4FAh LOAD:08048597 mov [ecx], ebx LOAD:08048599 mov ebp, 4 LOAD:0804859E add ecx, ebp LOAD:080485A0 sub edi, 1 LOAD:080485A6 cmp edi, 0 LOAD:080485A9 jnz short loc_804853C
L'idéal est encore une fois d'utiliser gdb pour laisser le programme s'auto-déchiffrer. La condition d'arrêt pourrait être la lecture de notre password. Pour cela, on va breaker une première fois après le read de notre password, et placer un watchpoint sur la zone mémoire dans laquelle il a été écrit.
$ gdb ./crackme-03 gdb$ b *0x080484ff Breakpoint 1 at 0x80484ff gdb$ r Starting program: /home/fab/Downloads/crackme-03 Enter password: AAAA --------------------------------------------------------------------------[regs] EAX: 0x00000005 EBX: 0xF7FA1FF4 ECX: 0x08048489 EDX: 0x00000009 o d I t s z a p C ESI: 0x00000000 EDI: 0x00000000 EBP: 0xFFFFCD2C ESP: 0xFFFFCD20 EIP: 0x080484FF CS: 0023 DS: 002B ES: 002B FS: 0000 GS: 0063 SS: 002B --------------------------------------------------------------------------[code] => 0x80484ff: mov esp,ebp 0x8048501: mov BYTE PTR [eax+0x8048488],0x0 0x8048508: mov ecx,0xc46981d 0x804850d: mov esi,DWORD PTR ds:0x8049d32 0x8048513: sub ecx,esi 0x8048515: mov DWORD PTR ds:0x8049d6e,ebp 0x804851b: sub ebp,0x2ec33d4e 0x8048521: mov ebp,DWORD PTR ds:0x8049d6e -------------------------------------------------------------------------------- Breakpoint 1, 0x080484ff in ?? () gdb$ rwatch *(0x08048489) Hardware read watchpoint 2: *(0x08048489) gdb$ c Continuing.
On break plus loin à la lecture de notre password. En regardant le code un peu avant, on voit une simple comparaison de chaines :
Hardware read watchpoint 2: *(0x08048489) Value = 0x41414141 0x08049c89 in ?? () gdb$ x/8i $eip-11 0x8049c78: mov edi,0x8049cde 0x8049c7d: mov esi,0x8048489 0x8049c82: mov ecx,0x9 0x8049c87: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] => 0x8049c89: jne 0x8049c92 0x8049c8b: call 0x8049ca9 0x8049c90: jmp 0x8049c99 0x8049c92: call 0x8049cc3 gdb$ x/1s 0x8049cde 0x8049cde: "YGL83WrU"
$ ./crackme-03 Enter password: YGL83WrU sh-4.2$