Mar 30 2008

HackIt! 2007 : nivel 6: solución

Published by admin at 12:48 am under Devel, HackIt, Seguridad

Reverse Engineering. Cracking. Un poco de conocimientoso sobre ambos temas serán imprescindibles para
pasar este nivel (os he dejado muchos días para que fuerais sacándolo por vuestra cuenta, ¿qué tal os ha ido?) Vamos a por ello. Tras descargarnos el fichero .zip que indica la página, lo descomprimimos e intentamos ejecutar (txipi nos dijo que no había virus ni código maligno en los ejecutables, por eso nos atrevemos a ejecutar un binario a pelo…). La salida es bastante pobre, por decir algo:


sh-3.2$ ./program
sh-3.2$

Así que toca depurar con GDB.


$ gdb ./program
warning: no loadable sections found in added symbol-file /tmp/program
(no debugging symbols found)

Vaya, si no hay tabla de símbolos, la depuración puede ser un infierno. Así que comprobemos primero que el ejecutable
no haya sido comprimido con UPX o similares (UPX es el compresor más conocido de ficheros ELF en Linux):


$ upx -l ./program
Ultimate Packer for eXecutables
Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007
UPX 3.00 Markus Oberhumer, Laszlo Molnar & John Reiser Apr 27th 2007
.
File size Ratio Format Name
-------------------- ------ ----------- -----------
532432 -> 52404 9.84% linux/elf386 ./program

¡Tachán! Efectivamente el ejecutable está comprimido con UPX. Descompresión al canto:


$ sh-3.2$ upx -d ./program
Ultimate Packer for eXecutables
Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007
UPX 3.00 Markus Oberhumer, Laszlo Molnar & John Reiser Apr 27th 2007
.
File size Ratio Format Name
-------------------- ------ ----------- -----------
532432 <- 52404 9.84% linux/elf386 program
Unpacked 1 file.

Y ahora volvemos a pasarlo por GDB, a ver qué nos dice:


sh-3.2$ gdb ./program
GNU gdb 6.6-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb)

Mejor :-) Bien, vamos a poner un punto de ruptura en main():


(gdb) break main
Breakpoint 1 at 0x8048455
(gdb)

Ejecutemos hasta el punto de ruptura y pidamos un desensamblado de la zona:

(gdb) run
Starting program: /tmp/program
Breakpoint 1, 0x08048455 in main ()
(gdb) disassemble
Dump of assembler code for function main:
0x08048444 : lea 0×4(%esp),%ecx
0×08048448 : and $0xfffffff0,%esp
0×0804844b : pushl 0xfffffffc(%ecx)
0×0804844e : push %ebp
0×0804844f : mov %esp,%ebp
0×08048451 : push %edi
0×08048452 : push %esi
0×08048453 : push %ebx
0×08048454 : push %ecx
0×08048455 : sub $0×78,%esp
0×08048458 : movl $0×0,0xffffffec(%ebp)
0×0804845f : lea 0xffffffd0(%ebp),%eax
0×08048462 : mov %eax,(%esp)
0×08048465 : call 0×804837c
0×0804846a : movl $0×0,0xffffffe8(%ebp)
0×08048471 : jmp 0×8048477
0×08048473 : addl $0×1,0xffffffe8(%ebp)
0×08048477 : cmpl $0×98967e,0xffffffe8(%ebp)
0×0804847e : jle 0×8048473
0×08048480 : lea 0xffffffc0(%ebp),%eax
0×08048483 : mov %eax,(%esp)
0×08048486 : call 0×804837c

Bien, se ve la zona de paso de variables a la pila (guardar el contexto) y primera llamada call (por el nombre de la función, times, parece que hace algún tipo de comprobación) y en función del resultado, en main+45 saltamos a main+51. Ahí nueva comparación… saltamos (hacia atrás) a main+47. Parece un bucle, ciclando hasta que se cumpla cierta condición. Posteriormente, se hace una nueva llamada a “times”, haciendo alguna nueva comprobación:


0x08048486 : call 0×804837c
0×0804848b : mov 0xffffffc0(%ebp),%edx
0×0804848e : mov 0xffffffd0(%ebp),%eax
0×08048491 : mov %edx,%ecx
0×08048493 : sub %eax,%ecx
0×08048495 : mov %ecx,%eax
0×08048497 : mov %eax,0xffffffe8(%ebp)
0×0804849a : cmpl $0xa,0xffffffe8(%ebp)
0×0804849e : jle 0×8048586
0×080484a4 : movl $0×80c89a8,(%esp)
0×080484ab : call

En main+90 hay alguna condición que tras comprobarla hace que el programa termine (salta a main+322). Vamos a cortocircuitar este último salto . a ver qué pasa ;-) :

(gdb) j *0x080484a4
Continuing at 0x80484a4.
username? jota
error: wrong serial number!
Program exited normally.
(gdb)
Vaya, algo hemos avanzado, porque al menos nos pide username… Pero poniéndole cualquier cosa (jota, p.ej.), vemos que no le gusta.
Mmmmmhhh… volvamos a la carga:


(gdb) run
Starting program: /tmp/program
.
Breakpoint 1, 0x08048455 in main()
(gdb) disassemble
...
0x080484ab : call 0×804835c
0×080484b0 : lea 0xffffffac(%ebp),%eax
0×080484b3 : mov %eax,(%esp)
0×080484b6 : call 0×804833c
0×080484bb : mov $0×303c48b1,%eax
0×080484c0 : sub 0xffffffec(%ebp),%eax
0×080484c3 : mov %eax,0xffffffec(%ebp)
0×080484c6 : addl $0×2faf080,0xffffffec(%ebp)
0×080484cd : cmpl $0×0,0xffffffec(%ebp)
0×080484d1 : jne 0×804857a
0×080484d7 : movb $0×9b,0xffffffe0(%ebp)


Entre el printf (”username”) y el gets (recogida del parámetro por teclado) no hay nada que destacar.
Lo siguiente termina en un jne a main+310. Volvamos a cortocircuitar (no queremos saltar en main+141… queremos ir
a la siguiente instrucción) :

(gdb) j *0x080484d7
Continuing at 0x80484d7.
correct! password = d3nb0r4
Program exited normally.
(gdb)

¡Qué bonito password! :-)

Trackback URI | Comments RSS

Leave a Reply

« Back to text comment