sábado, 9 de marzo de 2013

How to Exploit: GDB mas a fondo.. -3-

Vamos a retomar con este tercer paper, y analizar lo que hace nuestro humilde programa codeado en C.

Antes que nada, vamos a eliminar nuestro analizaMe compilado anteriormente, y vamos a volverlo a compilar con un parametro nuevo que es la option flag "-g".
Genera mayor informacion de debug para ser utilizada por GDB.
Let's work!.

$> gcc -g analizaMe.c -o analizaMe (compilas con option flag -g)
$> chmod +x analizaMe (le damos permisos de ejecucion)
$> ./analizaMe (ejecutamos el binario para testear que todo haya salido correcto y recordar que hacia)

La variable contar vale: 0
La variable contar vale: 1
La variable contar vale: 2
La variable contar vale: 3
La variable contar vale: 4


Ok, todo funciono bien por fuera, analicemos que hace por dentro, con lo aprendido anteriormente en GDB.

ACLARACION: Puede que las direcciones de memoria de SUS PCS respecto a las mias en estos ejemplos NO SEAN IGUALES. Y seria algo logico..
Asi que no se preocupen, que podran seguir igual los ejemplos...


$> gdb -q ./analizaMe (abrimos el binario creado con nuestro debugger favorito :))

(gdb) b main  (breakpoint en la funcion principal main)
Punto de interrupción 1 at 0x8048415: file analizaMe.c, line 4. (respuesta del gdb).

(gdb) r (corremos el programa con el comando run o r abreviado)
Breakpoint 1, main () at analizaMe.c:4
4      for(contar=0; contar < 5; contar++)


Bien como vemos, para en el punto de interrupcion que nosotros mismos pusimos en main.
Y como vemos nos adjunta '+ informacion' gracias al option flag -g que agregamos.

Bien, vamos a verificar como esta el panorama..

(gdb) i r $eip
eip            0x8048415    0x8048415 <main+9>  (verificamos la informacion del registro $eip y vemos que apunta a esa direccion).

(gdb) x/3i $eip
=> 0x8048415 <main+9>:    mov    DWORD PTR [esp+0x1c],0x0
      0x804841d <main+17>:    jmp    0x8048438 <main+44>
      0x804841f <main+19>:    mov    eax,DWORD PTR [esp+0x1c]



Como anteriormente vimos, la opción 'i' era la de instrucción. Le decimos a GDB que nos muestre solo las próximas 3 instrucciones a ejecutarse para guiarnos de que esta haciendo el programa y que va a hacer.
Si hicieron la tarea y refrescaron un poco assembler, fundamental para explotar cualquier vulnerabilidad... recordamos también cuando explique algunas instrucciones de assembler, como por ejemplo 'mov'.

A simple vista entonces, GDB nos dice que donde ahora mismo esta parado, va a realizar una operacion en la cual 'movera' el valor de la derecha '0x0' hacia la izquierda en donde tenemos como destino una direccion en memoria (esp+0x1c). Nota: Es muy comun ver este tipo de direcciones, porque si recordamos sabemos que EAX, EBX, EDI, ESI, ESP, etc son registros
y es comun leer ESP+4 o EBP-4 y cosas asi, este caso nos dice que lo va a mover a ESP+0x1c.
0x1c en decimal equivale a 28. Por lo que seria $esp+28.

Si recordamos tambien que el programa paro en nuestro breakpoint en main justo cuando comenzaba el for y nos arrojo esta informacion:
"4   for(contar=0; contar < 5; contar++)"
Podríamos deducir que ese valor 0x0 que va a mover, es el que le dimos en el FOR a nuestra variable llamada 'contar'.

Analicemos esa dirección de memoria que valor contiene en este momento con el programa pausado en nuestro breakpoint:

(gdb) i r $esp
esp            0xbffff270  (En el registro ESP encontramos una direccion de memoria 0xbffff270)

Por lo tanto BFFFF270 + 1C  (ESP+28) = BFFFF28C. (tranquilos, todo eso el debugger lo obvia por nosotros y lo sabe, pero para que entendamos, otra aclaracion for dummys, siempre que veamos 0x12345678 esa '0x' del principio nos indica que es una notacion Hexadecimal, la direccion seria 12345678.)

Bien, volviendo a la practica verificamos con GDB, la siguiente linea:
=> 0x8048415 <main+9>:    mov    DWORD PTR [esp+0x1c],0x0

(gdb) x/x $esp+0x1c
0xbffff28c:    0xb7fc1000

Como vemos nos responde lo que anteriormente les aclare, esp contiene una direccion y esa direccion + 28 (1c) es BFFFF28c, y GDB nos dice que esa direccion contiene el siguiente valor: 0xb7fc1000.

Por lo tanto lo que pasaria ahora es que al ejecutar la siguiente instruccion:
"mov    DWORD PTR [esp+0x1c],0x0" ..ese valor dejaria de existir y pasaria a ser 0x0 con la operacion de mov.

Voy a comentarles un nuevo comando el cual nos permite por asi decirlo, crear temporalmente un 'acceso directo' a una determinada direccion, para no tener que escribirla constantemente y verificar si tiene cambios en su contenido:

(gdb) print $esp+0x1c
$1 = (void *) 0xbffff28c

(Le decimos a gdb que nos cree una variable temporal de la direccion de memoria $esp+0x1c, para accederla facilmente cuando querramos, y gdb nos responde diciendo que se creo la variable $1)

Ahora usaremos el comando 'nexti' para ejecutar  la siguiente instruccion, nexti hace que el programa vaya paso a paso, instruccion por instruccion, luego del breakpoint que pusimos.

(gdb) nexti
0x0804841d    4      for(contar=0; contar < 5; contar++)

Ejecutamos nexti. Veamos si la direccion $esp+0x1c (0xbffff28c)    0xb7fc1000 que contenia valores aleatorios.. ha cambiado.

(gdb) x/x $1  
0xbffff28c:    0x00000000

Efectivamente, se cumplio la operacion 'mov' y movio el valor '0x0' a la direccion de esp+0x1c.
Veamos donde esta parado ahora el registro EIP y cuales son sus siguientes operaciones:

(gdb) x/10i $eip  (le decimos a gdb que nos arroje las proximas 10 instrucciones).



Como vemos en la imagen, EIP apunta a una instruccion en donde hay un JMP (JUMP), un salto el cual tiene como destino la direccion 0x8048438. Que es la 7ma linea de las 10 que pedimos que nos muestre. Le damos a nexti.

(gdb) nexti
0x08048438    4      for(contar=0; contar < 5; contar++)

Vemos que seguimos en el FOR.

(gdb) x/3i $eip
=> 0x8048438 <main+44>:    cmp    DWORD PTR [esp+0x1c],0x4
      0x804843d <main+49>:    jle    0x804841f <main+19>
      0x804843f <main+51>:    leave

Ok, confirmamos que salto a la direccion 8048438 como sabiamos.
Y ahora lo que va a hacer es a comparar mediante la instruccion 'cmp'. El valor 0x4 (4) contra el valor que esta guardado en la direccion [esp+0x1c] (nuestra famosa direccion que podemos acceder temporalmente mediante la variable $1 que seteamos anteriormente).
Como sabemos por la ultima vez que vimos la direccion esa contenia el valor '0'. Por lo tanto comparara el valor 4, contra el valor 0. Exactamente en esta parte del FOR estamos: "contar < 5"
Le damos a nexti...

(gdb) nexti
0x0804843d    4      for(contar=0; contar < 5; contar++)

(gdb) x/i $eip
=> 0x804843d <main+49>:    jle    0x804841f <main+19>

Luego de ejecutar 'nexti' nos lleva a la siguiente instruccion, y si la verificamos con examine para ver donde esta parado EIP, nos encontramos con un JLE. Como recordamos, J.. es sinonimo de JUMP, pero en este caso es un salto 'condicional' que significa JUMP LESS EQUAL.
Y quiere decir que SALTA, SI ES MENOR o IGUAL.....

Como evidentemente esto es cierto, ya que 0 es menor que 4.. entonces salta a la direccion 0x804841f.

(gdb) x/i $eip
=> 0x804841f <main+19>:    mov    eax,DWORD PTR [esp+0x1c]

Estábamos en lo correcto, y salto nomas a la direccion previamente dicha.
Si verificamos las siguientes 10 instrucciones:



Observamos que en la 4ta linea de las 10 solicitadas, hay un "CALL 0x80482F0".
Que es el encargado de llamar a la funcion PRINTF. (La que imprime en pantalla el primer mensaje de "La variable contar vale: 0" que observamos al ejecutar el programa).

Para que se entienda, cuando llegamos a una instruccion donde hay un CALL como en este caso el programa se desvia a una subrutina, es como si fuese una porcion de codigo aparte en la cual se realizan otras operaciones y una vez que se concluyen al final de ese codigo de la subrutina hay una instruccion llamada RET (de return/regreso).
Vean la siguiente imagen..















 Por lo tanto, luego de la llamada a esa funcion, el RET deberia dejarnos justito en la siguiente direccion 0x8048433:













 Ok, siguiendo con nuestro analisis, ya estamos por el final, espero no se hayan perdido.

(gdb) x/5i $eip
=> 0x8048433 <main+39>:    add    DWORD PTR [esp+0x1c],0x1
      0x8048438 <main+44>:    cmp    DWORD PTR [esp+0x1c],0x4
      0x804843d <main+49>:    jle    0x804841f <main+19>
      0x804843f <main+51>:    leave
      0x8048440 <main+52>:    ret

EIP apunta a una instruccion conocida llamada 'add' la cual sirve para 'sumar' dos operandos y lo guarda en el lugar destino, en este caso 0x1 en nuestra conocida direccion de memoria ;).

Le damos a 'nexti'.. y luego verificamos despues de esta operacion si el valor de esa direccion de memoria tuvo algun cambio..

(gdb) nexti
0x08048438    4      for(contar=0; contar < 5; contar++)

(gdb) x/x $1
0xbffff28c:    0x00000001

Efectivamente.. ahora contiene el valor de 1.
Si miramos un poco mas las siguientes dos instrucciones:

(gdb) x/2i $eip
=> 0x8048438 <main+44>:    cmp    DWORD PTR [esp+0x1c],0x4
      0x804843d <main+49>:    jle    0x804841f <main+19>

Ya nos resulta conocida, y es que esta nuevamente comparando el valor de 4 con el ahora 1.
Luego viene el ya explicado JLE - va a saltar si es menor o igual que 4.
Como lo és, salta a 0x804841f. Y así seguiría el loop.. hasta que si seguimos analizando el programa paso a paso con nexti y verificando el valor de la direccion en $1.. llegaríamos a:

(gdb) x/x $1
0xbffff28c:    0x00000005

(gdb) x/i $eip
=> 0x8048438 <main+44>:    cmp    DWORD PTR [esp+0x1c],0x4

(gdb) x/5i $eip
=> 0x8048438 <main+44>:    cmp    DWORD PTR [esp+0x1c],0x4
      0x804843d <main+49>:    jle    0x804841f <main+19>
      0x804843f <main+51>:    leave
      0x8048440 <main+52>:    ret


Luego de ir sumándole 1 por cada loop de imprimir en pantalla, nuestra famosa dirección contiene el valor de 5.
Por lo tanto al siguiente 'cmp', de comparar si 5 es menor o igual que 4? y matemáticamente es negativo, NO se cumpliría el JLE condicional por lo que las siguiente dos instrucciones serian:

(gdb) x/2i $eip
=> 0x804843f <main+51>:    leave
      0x8048440 <main+52>:    ret
      0xb7e344d3 <__libc_start_main+243>:    mov    DWORD PTR [esp],eax
      0xb7e344d6 <__libc_start_main+246>:    call   0xb7e4dfb0 <exit>

(gdb) nexti
[Inferior 1 (process 5324) exited with code 034]

De esta manera finaliza el tercer paper.. y uno de los mas largos.
Gracias :).


#c0nfused - allmenage@gmail.com - http://insecuritynotes.blogspot.com


No hay comentarios:

Publicar un comentario

Deja un comentario..