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

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

Debido a que hay personas a las que les ha parecido interesante la introducción a la ingeniería inversa en linux, voy a seguir publicando mis progresos en esta rama de la seguridad informática.

Lo que voy a hacer hoy,  va a ser analizar otro crackme (más complicado que el anterior) que he encontrado en la página http://www.crackmes.de .

Concretamente, el crackme que vamos a usar ahora lo podéis encontrar en esta dirección : http://www.crackmes.de/users/lord/easy_linux_crackme/ .

Bueno, una vez que lo habéis descargado y le habéis asignado permisos de ejecución vamos a proceder al análisis.

Lo primero que vamos a hacer es ejecutarlo y ver que pasa.

[Familia@linuxArriba inge]$ ./cm1eng
Password : 123456

[Familia@linuxArriba inge]$

Lo primero que podemos observar es que mi nombre de usuario es Familia, lo es xD .No nos muestra ningún mensaje de ningún tipo por lo que podemos pensar que no hemos acertado la contraseña. Ahora, vamos a aplicarle el comando strings para ver si está guardada la contraseña en texto plano.

[Familia@linuxArriba inge]$ strings cm1eng

Password :

Great you did it !:)

QTBXCTU

[Familia@linuxArriba inge]$

Y en este momento yo ya pensé que se acababa el crackme porque habíamos encontrado la contraseña (QTBXCTU), pero si la probáis veréis que el programa hace los mismo que con cualquier otra contraseña (bueno, no cualquier otra, por eso estamos intentando crackearlo).

Como no hemos tenido éxito , vamos a proceder a desensamblarlo.

Para desensamblar el binario vamos a usar el programa objdump que probablemente ya os venga instalado en vuestra distribución de linux. Para desensamblar, ejecutamos el siguiente comando: “objdump -d cm1eng

He pegado la salida del comando en pastebin porque quizás aqui no quedaba muy bien. Podéis verla aquí : http://pastebin.com/MbypxFXL .

Antes de continuar os voy a enseñar una cosa importante de ASM en linux. Cada vez que se hace la interrupción 0x80, lo que se hace es llamar a una syscall. Dicho muy mal y pronto, una syscall es como una función de la API del sistema linux ( o cualquier unix-based system ). Por ejemplo, hay algunas syscalls que sirven para escribir (ya sea en la pantalla, en ficheros …) , otras para cambiar el permiso de archivos , para crear threads … Aquí podemos encontrar una lista con syscalls http://fxr.watson.org/fxr/source/kern/syscalls.c. Cada syscall tiene asignada un número que será muy importante para identificarla.

El procedimiento para llamar a una syscall en assembly sería algo así:

  1. Guardar en eax el número de la syscall (imaginemos que queremos usar  la syscall write, cuyo número es 4): “mov $4, %eax
  2. En ebx se guarda el primer parámetro (en nuestro caso es un file descriptor, y como nosotros queremos escribir en la standart output elegimos el 1): “mov $1 , %ebx
  3. En ecx el 2º parámetro. En la syscall write es el mensaje, osea que le pasamos la dirección de nuestra string : “mov $0xblabla, %ecx
  4. En edx el 3º parámetro (así consecutivamente). En write() sería la longitud del mensaje, si el mensaje fuera hola sería: “mov $4,%edx
  5. Llamar a la interrupción 0x80. “int 0x80

Osea, siempre que veamos un  “int 0x80” tenemos que saber que se está haciendo una syscall y tenemos que ver que es lo que hacen esas syscalls.

Bueno, ahora que podemos analizar el código vemos que al principio hay dos syscalls, que son write() y read() y por la ejecución del programa sabemos que esa es la parte que se encarga de mostrarnos el “Password :” y de leer la contraseña que pongamos. Si no me creéis podéis mirar en las direcciones de memoria que vienen ahí.  Luego vemos esto :

mov    $0x8049126,%esi

Si desde el gdb miramos que hay en esa dirección de memoria (printf “%s\n” , 0x8049126 o x/s 0x8049126) veremos que se encuentra la string “QTBXCTU” que intentamos meter antes como contraseña. En la siguiente línea se copia el contenido de %esi (la string) al registro %edi y en la siguiente, se pone a 0 el registro %ebx que veremos que va a funcionar como un contador.

Poniéndonos a mirar el resto del código , podemos notar que desde la dirección 0x80480b6 hasta 0x80480c3 hace lo siguiente :

  1. :Cifra
  2. Guarda el byte número %ebx de la cadena de %esi en %al
  3. %al = %al xor 0x21
  4. Guarda %al en su sitio correspondiente en %edi (posición %ebx)
  5. %ebx = %ebx+1
  6. Si %ebx es igual 7 continúa, si es distinto vuelve a Cifra.

Tras eso, vemos que guarda nuestra cadena (la que hemos insertado nosotros, sabemos cual es debido a que la pasa como parámetro en la syscall read (3)) en el registro %esi y luego guarda la cadena ya modificada.  Luego compara los primeros 7 bytes de las cadenas y si coinciden, veremos el cartel del chico bueno, si no coinciden saldrá directamente.

Tras ver esto, hay dos soluciones :

  1. Poner un breakpoint en alguna dirección de memoria en la que ya se haya modificado la cadena y ver la cadena.
  2. Cifrar nosotros la cadena a mano(quien dice a mano dice hacerse un programita para verlo)

Yo como me imagino que no tenéis ningún problema con la programación pero que puede ser distinto con el manejo de debuggers voy a optar por la primera.  La dirección en la que voy a poner el breakpoint va a ser en 0x80480c5 porque es ahí donde va cuando %ebx es igual a 7 y por lo tanto ya ha acabado la rutina de cifrado.

Abrimos el programa con el gdb ( “gdb cm1eng” ) y para poner el breakpoint lo hacemos así:

(gdb) break *0x80480c5

Breakpoint 1 at 0x80480c5

(gdb) run #corremos el programa

Nos saldrá de nuevo el prompt para meter la contraseña y cuando metamos la que sea llegará al breakpoint. En ese momento, la string a la que se va a comparar nuestra string ya está modificada y solo tenemos que ver su contenido. Si miráis el código, veréis que esa string se encuentra en la dirección 0x8049126.

(gdb) x/s 0x8049126

0x8049126: “pucybut”

Fuck yeah! Ya tenemos ahí nuestra contraseña de nuevo. Si nos vamos a ejecutar el programa:

[Familia@linuxArriba inge]$ ./cm1eng
Password : pucybut

Great you did it !:)
[Familia@linuxArriba inge]$

 

Finalmente hemos conseguido reventar la protección de este crackme.

Espero que les haya gustado esta nueva parte y en la próxima parte aprenderemos como parchear binarios de este tipo para poder conseguir el cartel de chico bueno sin siquiera saber la contraseña.

Anuncios

Acerca de Braulio

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

One response to “Introducción a la ingeniería inversa en linux (II)

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: