miércoles, 6 de marzo de 2013

#How to exploit: Un poco de Assembler y GNU Debugger. -2-

#How to exploit: Un poco de Assembler y GNU Debugger. 




Retomando con el paper anterior, y nuestro código de ejemplo, vamos a repasar un poco sobre Assembler y GNU Debugger durante esta segunda parte. Veremos por 'encima' el tema de assembler ya que mi interes no es un tutorial de este, sino repasarlo para introducirlo con el Debugger.

Para invocar al GDB
Utilizaremos el crudo y puro gdb desde la linea de comandos con sintaxis INTEL. 
Para configurar GDB con sintaxis INTEL, vamos a hacer lo siguiente:


$> sudo gedit /etc/gdb/gdbint 

Y luego pegamos al final la siguiente linea y guardamos el archivo:

set disassembly-flavor intel

La sintaxis de intel nos mostrara las operaciones de esta manera en gdb:

instrucciones "[destino],[origen]" 
Por ejemplo: "mov ebx, eax"


En este ejemplo el valor del registro 'eax', sera movido al registro 'ebx'. 
Recordar que las operaciones del origen y destino pueden ser un valor, 
una dirección de memoria, o un registro como en este caso.

Operaciones comunes que veremos en assembler para refrescar memoria:

MOV: Mueve contenido
INC: Incrementa de a 1 el valor
DEC: Resta de a 1 el valor
ADD: Suma  
SUB: Resta
CMP: Compara dos registros o un registro y direccion de memoria.
JMP/JNE etc: Todos los que empiecen con J.. son saltos condicionales e inccondicionales. 
Hay mas pero como dije, son los basicos y el paper no esta orientado a un manual de assembler.


 

# GDB

El debugger es una herramienta que nos permite ejecutar programas y analizarlos. Ya sea para localizar errores o entender un poco mas a fondo que es lo que hace una determinada aplicación.

GDB dispone de un comando muy particular y uno de los mas útiles a la hora de verificar la memoria.
Este comando se llama 'examine' y como su nombre indica, nos sirve para examinar la memoria.
GDB puede examinar detenidamente cada aspecto de la ejecución de un programa, ejecutarlo, detenerlo, verificar los registros, direcciones de memoria, lo que se nos ocurra.
(Lo practico de GDB también es que la mayoría de los comandos se pueden 'abreviar', por ejemplo examine se puede acortar a una simple 'x' y este se reconoce como un comando)

El comando examine, tiene varias maneras de arrojar la información que requerimos ver en una determinada direccion de memoria. Podemos especificar el formato en el que se muestra usando alguna de las siguiente abreviaturas:

x = Muestra el resultado en Hexadecimal
u = Muestra el resultado en Decimal.
o = Muestra el resultado en Octal.
t = Muestra el resultado en Binario.


Veamos un ejemplo con nuestro pequeño programa del paper anterior que adjunto nuevamente:

-----------------------------------------------------
#include <stdio.h>
int main() {
  int contar;
  for(contar=0; contar < 5; contar++)
  {
    printf("La variable contar vale: %i \n", contar);
  }
}

-----------------------------------------------------


$> gdb -q ./analizaMe
De esta manera le pasamos a gdb el binario a debugguear.

(gdb) break main
Punto de interrupción 1 at 0x804840f (en mi caso esto nos responde gdb al poner un break)

Le decimos que genere un breakpoint en la funcion principal "main". Un breakpoint no hace otra cosa que poner una barrera una vez que se ejecuta el programa, le dice al gdb que cuando llegue a nuestro breakpoint el programa se parara obligatoriamente ahi en ese break. Podemos poner varios break, de momento solo haremos uno en la funcion main.

(gdb) run
Breakpoint 1, 0x0804840f in main () (esto nos responde el gdb al encontrar el break que seteamos)

Corremos el programa desde el debugger con run o tambien con una simple 'r' y va a parar en el primer breakpoint que seteamos en la funcion "main"

(gdb) info register

eax            0x1    1
ecx            0xbffff344    -1073745084
edx            0xbffff2d4    -1073745196
ebx            0xb7fc1000    -1208217600
esp            0xbffff2a8    0xbffff2a8
ebp            0xbffff2a8    0xbffff2a8
esi            0x0    0
edi            0x0    0
eip            0x804840f    0x804840f <main+3>
eflags         0x246    [ PF ZF IF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51


Este comando "info register" nos permite ver el estado actual de los registros.
Como ven obtenemos un status de todos los registros de ese preciso momento.

(gdb) info register eip
eip            0x804840f    0x804840f <main+3> (respuesta del gdb)

Podemos filtrar a algun registro en particular escribiendolo al lado como en el ejemplo 'eip'.
Ademas, como les conte antes podemos 'abreviar' este comando asi: "i r eip"
Vemos como EIP contiene el valor 0x804840f.

(gdb) x/x $eip
0x804840f <main+3>:    0x83f0e483 (ahora examinamos la memoria a la que esta señalando el registro EIP usando la direccion almacenada en EIP). Vemos que donde arriba EIP contenia '0x804840f', examinamos este registro y contiene lo siguiente: 0x83f0e483.

De esa manera usamos el 'examine' abreviado con la primer 'x', luego le decimos que nos arroje la info en hexadecimal con la segunda 'x'. Y el registro 'eip'. Fijense que en este caso hay que poner el registro luego de un $. A diferencia de el info register que no lo anteponiamos.

Tambien se puede anteponer un numero al formato del comando examine, para examinar varias unidades en esas direcciones objetivos que tengamos. Por ejemplo:

(gdb) x/4x $eip
0x804840f <main+3>:    0x83f0e483    0x44c720ec    0x00001c24    0x19eb0000

Las unidades tienen un tamaño predeterminado de 4 bytes. Conocidas como WORD.
De la misma manera que podemos cambiar el formato que nos arroja el resultado con 'examine' ya sea en hexadecimal, octal, binario o decimal, tambien podemos cambiar el tamaño de las unidades que estamos examinando, agregandole una letra de tamaño al final de la de formato y estos son:

b: byte
h: half-word (2 bytes)
w: word (4 bytes)
g: giant o qword (8 bytes)



Veamos un ejemplo practico:

1) (gdb) x/4xb $eip
0x804840f <main+3>:    0x83    0xe4    0xf0    0x83

2) (gdb) x/4xh $eip
0x804840f <main+3>:    0xe483    0x83f0    0x20ec    0x44c7

3) (gdb) x/4xw $eip
0x804840f <main+3>:    0x83f0e483    0x44c720ec    0x00001c24    0x19eb0000

4) (gdb) x/4xg $eip
0x804840f <main+3>:    0x44c720ec83f0e483    0x19eb000000001c24
0x804841f <main+19>:    0x042444891c24448b    0xe8080484e82404c7


1- Como vemos en el ejemplo uno, le decimos a gdb que nos examine el registro $eip, y nos arroje en 4 unidades, en hexadecimal, y en tamaño byte.
2- En el segundo de la misma manera pero ya con 2 bytes.
3- Igual pero con 4 bytes.
4- Por ultimo igual, pero con 8 bytes.

  • Resumen de este paper
  1. Ya sabemos, compilar un codigo fuente, gcc analizaMe.c.
  2. Sabemos invocar el gdb y pasarle un binario para debuggearlo: gdb -q ./analizaMe
  3. Sabemos que para poner un breakpoint y que se detenga el programa invocamos el comando 'break' + nombre de la función, o dirección en memoria donde queremos que pare.
  4. Sabemos que una vez que para en el breakpoint, podemos verificar el status de los registros mediante 'info register' o alguno en particular como en nuestro caso anterior 'info register eip'.
  5. Sabemos que la herramienta 'examine' nos permite verificar todas la memoria, direcciones y valores que se nos ocurra y arrojar el resultado de la manera que mas comoda nos parezca, como en el ejemplo de 'x/x $eip' para ver el valor que contiene el registro EIP en ese momento y que nos arroje el resultado en hexadecimal.
  6. Sabemos como mostrar por unidades como "x/2x"
  7. Sabemos como mostrar examine en tamaño de unidades b,h,w,g (byte, 2bytes,4bytes, 8bytes).

De momento dejamos acá esta segunda parte, y ya pronto escribo la tercera.
c0nfused.

No hay comentarios:

Publicar un comentario

Deja un comentario..