Introducción a la ingeniería inversa en linux (I)

Esta es la parte 1, podéis ver la 2 aquí .

La ingeniería inversa es un tema que siempre me ha llamado la atención aunque nunca me he sentido muy cómodo en ella.  Esta mañana me propuse el reto de crear un crackme a modo de ejemplo y conseguir crackearlo. Lo he conseguido (a muchos no les parecerá algo muy difícil, pero para mi es un mundo) y voy a mostraros como lo he hecho.

Antes de nada, para seguir esta introducción necesitaremos una distribución de linux (obvio) , gdb (suele venir instalado en todas las distros) y el paquete gcc-g++ para compilar nuestro crackme. Serán casi necesarios conocimientos de C/C++ y de ASM será útiles aunque no obligatorios.

Empecemos. Este va a ser el código de nuestro primer crackme :

#include <iostream>
#include <string.h>

using namespace std;

int main()
{
char palabra[50];

cout << » Cual es la contrasenia ?? » << endl;
cin >> palabra;

if (!strcmp(palabra,»alfffamola»))
{
cout<< » Yeeeeahh!! Tu tambien molas» <<endl;
}
else
cout<< «Pues esa no es la contrasenia» <<endl;

return 0;
}

Es verdaderamente sencillo y me imagino que no hacer falta que lo explique.  Bueno, nos disponemos a compilar con » g++ crackme.cpp -o crackme « y ya tenemos nuestro crackme ejecutable.

Veamos, nuestro objetivo va a ser encontrar donde está la «contraseña», en este caso «alfffamola» . Para eso, nos vamos al debugger :

$ gdb crackme

Y lo primero que vamos a hacer va a ser desensamblar la función main, lo hacemos de esta forma :

(gdb) disas main
Dump of assembler code for function main:
0x080486d4 <+0>:     push   %ebp
0x080486d5 <+1>:     mov    %esp,%ebp
0x080486d7 <+3>:     and    $0xfffffff0,%esp
0x080486da <+6>:     sub    $0x50,%esp
0x080486dd <+9>:     movl   $0x80488a4,0x4(%esp)
0x080486e5 <+17>:    movl   $0x8049c00,(%esp)
0x080486ec <+24>:    call   0x80485c8 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x080486f1 <+29>:    movl   $0x80485f8,0x4(%esp)
0x080486f9 <+37>:    mov    %eax,(%esp)
0x080486fc <+40>:    call   0x80485e8 <_ZNSolsEPFRSoS_E@plt>
0x08048701 <+45>:    lea    0x1e(%esp),%eax
0x08048705 <+49>:    mov    %eax,0x4(%esp)
0x08048709 <+53>:    movl   $0x8049b60,(%esp)
0x08048710 <+60>:    call   0x80485d8 <_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_@plt>
0x08048715 <+65>:    movl   $0x80488c0,0x4(%esp)
0x0804871d <+73>:    lea    0x1e(%esp),%eax
0x08048721 <+77>:    mov    %eax,(%esp)
0x08048724 <+80>:    call   0x8048608 <strcmp@plt>
0x08048729 <+85>:    test   %eax,%eax
0x0804872b <+87>:    jne    0x8048753 <main+127>
0x0804872d <+89>:    movl   $0x80488cb,0x4(%esp)
0x08048735 <+97>:    movl   $0x8049c00,(%esp)
0x0804873c <+104>:   call   0x80485c8 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x08048741 <+109>:   movl   $0x80485f8,0x4(%esp)
0x08048749 <+117>:   mov    %eax,(%esp)
0x0804874c <+120>:   call   0x80485e8 <_ZNSolsEPFRSoS_E@plt>
0x08048751 <+125>:   jmp    0x8048777 <main+163>
0x08048753 <+127>:   movl   $0x80488e8,0x4(%esp)
0x0804875b <+135>:   movl   $0x8049c00,(%esp)
0x08048762 <+142>:   call   0x80485c8 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x08048767 <+147>:   movl   $0x80485f8,0x4(%esp)
0x0804876f <+155>:   mov    %eax,(%esp)
0x08048772 <+158>:   call   0x80485e8 <_ZNSolsEPFRSoS_E@plt>
0x08048777 <+163>:   mov    $0x0,%eax
0x0804877c <+168>:   leave
0x0804877d <+169>:   ret
End of assembler dump.
(gdb)

Y ahí podemos ver varias cosas importantes, main+24, refiere al primer cout; main+60, al cin;  luego en main+104 y en main+142 están los cout de «tu tambien molas» y «pues esa no es la contraseña». Pero lo más impmortante de todo, es la llamada a strcmp en main+80. Ahí es donde se hace la comparación de las cadenas y se comprueba si la contraseña ingresada es válida.

Algunos conceptos que tenemos que tener claros son :

  • En ASM, los parámetros de las funciones se pasan moviendo las direcciones de estos a la pila, y luego ejecutando el call.  En ESP estará el primer parámetro y en ESP+4 estará el segundo parámetro (así consecutivamente).
  • En linux se usa el ASM AT&T osea, que :» mov %eax, %ebx » copia %eax en %ebx y no al revés.

Nosotros tenemos que ver los parámetros que se le pasan a la función strcmp() porque ahí estarán la cadena que nosotros ingresemos y nuestra ansiada contraseña. Como la contraseña es el segundo parámetro, en el momento de llamar a strcmp() estará en ESP+0x4. Si nos ponemos a ver los movimientos que hay antes de la llamada a strcmp() podemos ver uno muy interesante : «movl   $0x80488c0,0x4(%esp)» . Esa instrucción es la que mueve una dirección a ESP+4, que es la dirección en la que tiene que estar la contraseña, por lo tanto, ¡en 0x80488c0 está nuestra querida contraseña! Vamos a comprobarlo :

(gdb) printf «%s\n» , 0x80488c0
alfffamola
(gdb)

Fuck Yeah! hemos encontrado nuestra contraseña sin siquiera ejecutar el programa. Ahora solo nos quedaría ejecutar el programa de nuevo e ingresar «alfffamola» para saber que nosotros también molamos.

También existe un método que es bastante sencillo pero con el que se aprende bastante menos que es usar el comando strings.

[braulio@linuxArriba inge]$ strings crackme
/lib/ld-linux.so.2
libstdc++.so.6
__gmon_start__
_Jv_RegisterClasses
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
_ZSt4cout
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
_ZNSt8ios_base4InitC1Ev
_ZSt3cin
_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_
_ZNSt8ios_base4InitD1Ev
_ZNSolsEPFRSoS_E
libm.so.6
libgcc_s.so.1
libc.so.6
_IO_stdin_used
__cxa_atexit
strcmp
__libc_start_main
GLIBC_2.0
GLIBC_2.1.3
GLIBCXX_3.4
PTRh@
[^_]
Cual es la contrasenia ??
alfffamola
Yeeeeahh!! Tu tambien molas
Pues esa no es la contrasenia

Y ahí se ven las strings estáticas del programa. Como ahí la única que llama la atención es alfffamola, esa sería la primera que probaríamos (al menos yo lo haría así).

Bueno, aquí es donde acaba esta pequeña introducción.

Acerca de Braulio

"CEO" de Alfffa Solutions Ver todas las entradas de Braulio

5 respuesta a «Introducción a la ingeniería inversa en linux (I)»

Replica a toño Cancelar la respuesta