martes, 15 de enero de 2013

Reproducción y explotación del CVE-2010-3333 - BoF en MS Word (Parte I)

*************************************************************************************************
- Reproducción y explotación del CVE-2010-3333 - BoF en MS Word (Parte I)
- Reproducción y explotación del CVE-2010-3333 - BoF en MS Word (Parte II)
*************************************************************************************************

Hace ya bastante tiempo me llego un correo electrónico a mi bandeja de SPAM un tanto sospechoso (con archivo adjunto incluido), con afán de investigar un poco más en el asunto lo aparqué y lo apunté en mi “lista de tareas futuras”, esa que nunca se acaba. Y como ya hacia un tiempo que no pasaba por aquí, he decidido retomar ese correo electrónico, echarle un ojo y empezar el año con fuerza ;)

El email venía acompañado de un fichero en formato “.doc” que al abrirlo con un editor hexadecimal nos encontrábamos con lo siguiente:

image

Tal y como se puede observar en la captura anterior dicho fichero no contiene un formato clásico de un documento “DOC”, si no que contiene las cabeceras del formato RTF. Fue entonces cuando me vino a la cabeza la vulnerabilidad que apareció en Noviembre del 2010 y que afectaba a Microsoft Word, provocando un Stack Buffer Overflow en el procesado de los ficheros RTF, la cual fue clasificada como crítica y se le asignó el siguiente CVE: CVE-2010-3333.

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.

Fase de Reproducción:

Con el fin de poder entender con exactitud cómo funciona dicha vulnerabilidad, centraré éste artículo en el estudio de la misma y como poder explotarla posteriormente.

La vulnerabilidad es posible gracias a un erróneo parseado del atributo “pFragments” del formato RTF. Partiendo de la base que nuestra cabecera fija del fichero debe ser algo similar a la siguiente estructura, “{\rtf1{\shp{\sp{\sn pFragments}{\sv X;Y;”, dónde “X” debe ser un valor decimal diferente a “2, 4 o 8” e “Y” un valor decimal. A partir de aquí vamos a visualizar cómo se comporta winword.exe si seguidamente de esta estructura le añadimos una ristra de valores en hexadecimal. (Hay que tener en cuenta que en el formato RTF han de ponerse los caracteres en su codificación en hexadecimal, por lo que, si queremos introducir una “X” deberemos poner el valor “58”).

 
import os
Ini_file = "{\\rtf1{\shp{\sp{\sn pFragments}{\sv 1;4;"
Padding = "58" * 50000
End_file = "}}}}"
exploit = Ini_file + Padding + End_file
# Create File
f = open("exploit_cve-2010-3333_word_2007.doc", "wb")
f.write(exploit)
print "Exploit RTF file created!!"
f.close()

Si abrimos el fichero mediante Immunity Debugger:

image

Tal y como se puede observar, la aplicación está dando un error de violación de segmento ya que la instrucción señalada no puede acceder al valor del registro “EAX = F592B8B0”,esto es debido a que en instrucciones anteriores, nuestra ristra de “58” está modificando el valor utilizado en EAX. Para llegar a nuestro objetivo vamos a retroceder en el árbol de funciones que llaman a la dirección que nos provoca el error, de este modo estudiaremos qué está pasando.

Debido a que la dirección dónde se está produciendo el error se encuentra asociada a la librería “MSO.DLL”, y ésta tiene activada la protección ASLR, desactivaremos dicha protección mediante la herramienta setdllcharacteristics de Didier Stevens para facilitar la tarea de debugger. (Únicamente se desactivará para facilitar el debug de la aplicación, a la hora de desarrollar el exploit dicha protección será activada de nuevo).

image

Para averiguar dónde se está modificando nuestro valor EAX anteriormente nombrado extraemos el árbol de funciones que llaman a la que produce el error:

image

Si investigamos la rama de la izquierda (sub_32E69BDA, sub_32E69AB6 y sub_32E69973) de menos a más, nos topamos con algo que llama bastante la atención.

1) Sub_32E69973:

image

En la función “sub_32E69973”, predecesora de la que nos devuelve el error, nos topamos con una comparación de cadenas dónde aparece nuestra ristra de “58”s, en el caso que la comparación sea falsa, la aplicación salta a la función dónde nos devuelve el error, ¿pero y si trucamos dichos valores modificándolos a “00000000” y hacemos que la comparación sea verdadera?

image

Bingo!! la aplicación ha sufrido un Stack Buffer Overflow y hemos conseguido sobrescribir el registro EIP. Por lo que, nuestro siguiente objetivo es ver qué valores son los de la instrucción CMP y sustituirlos en la ristra por 0’s.

Para visualizar el valor exacto utilizaremos como ristra la opción pattern_create de mona.py o metasploit, precedida de un entero (55*24) tal y como nos indicaban las especificaciones del formato.

...
Length = "55" * 24
junk = "Aa0Aa1Aa2Aa3Aa4Aa5....q0Aq1Aq2Aq3Aq4Aq5Aq".encode("hex")
...

2) Sub_32E69AB6:

Si introducimos un breakpoint en la función “sub_32E69AB6” nos topamos con la instrucción “CALL DWORD PTR DS: [EAX+1C]”, la cual nos hace saltar a una parte de código bastante interesante.

image

La función memcpy() señalada en el código anterior, es la función “culpable” de copiar parte del fichero a nuestra STACK, y debido a que no se está controlando el tamaño de los bytes a copiar, es posible realizar un Stack Buffer Overflow.

image  

En la captura anterior se puede observar el destino, origen y el tamaño de los bytes que se van a copiar.

Si proseguimos con la ejecución de las funciones, volveremos a encontrarnos con la instrucción de CMP (compare), pero esta vez la cadena que compara con “0x00000000” es “0x61413761”, que decodificado es “a7Aa” (recordad que es Little-endian). Solo nos falta localizar dicha cadena en nuestra ristra de caracteres y sustituirla por zeros.

image

Modificamos el exploit:

...
Length = "55" * 24
Padding = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6A".encode("hex")
Null = "00" * 4
Junk = "a7Aa8Aa9Ab0Ab1A......Aq3Aq4Aq5Aq".encode("hex")
...

Ya hemos conseguido bypassear la instrucción CMP y al proseguir con la ejecución del proceso llegamos a sobrescribir el registro EIP con un nuevo valor “31614130 == hex(‘0Aa1’)”, que coinciden con los valores 3,4,5 y 6 de la variable “Padding”.

image

Ahora que controlamos el registro EIP, solo nos queda introducir a nuestro exploit la ShellCode, pero existe un “problema”, debido a que estamos trabajando sobre el sistema operativo Windows 7 y Microsoft Office 2007 debemos bypassear las protecciones DEP (Data Execution Prevention) y ASLR (Address space layout randomization) para poder ejecutar código.

3) Bypass ASLR

En realidad no podemos llamar evadir ASLR a la técnica que se va a aplicar, ya que únicamente nuestro objetivo va a ser buscar una librería que no disponga de esta protección, y así poder llamar a sus direcciones que se cargarán de forma estática.

Para encontrar dicha librería podemos hacerlo de distintos modos:

1) La herramienta process-explorer de sysinternals nos ofrece dicha información:

image

2) O utilizar el script mona.py y así extraer información de las librerías que carga el proceso winword.exe.

image

Entre todas las librerías que carga el proceso, únicamente existe una que no disponga de la protección ASRL, por lo que, deberemos utilizar esta librería “msxml5.dll” para evadir la siguiente protección.

4) Bypass DEP

En la entrada dónde se vio cómo bypassear la protección DEP con la función SetProcessDEPPolicy(), vimos cómo de una forma sencilla podemos evadir DEP No Permanente, ya que dicha función únicamente nos permite eludir este modo de la protección.

Para ir un poco más allá, hoy utilizaremos la función VirtualProtect(), que nos permite eludir cualquier modo en las que se puede configurar DEP.

De igual modo que se hizo para construir la cadena ROP con la función SetProcessDEPPolicy, nos ayudaremos de los registros y la instrucción PUSHAD para bypassear DEP con la función VirtualProtect().

Un ejemplo de cómo realizar cadenas ROP mediante VirtualProtect(), puede ser el siguiente.

image

Puede resultar extraño el valor del registro EBP, ya que si miramos los parámetros que debemos enviar a la función VirtualProtect(), no debería estar ahí, pero dicha dirección es utilizada para una vez finalizada la función VirtualProtect() se ejecutará esta dirección de memoria, y como nuestro objetivo es llegar a nuestra ShellCode, añadimos la instrucción “Call/Jmp ESP” para saltar a ella.

Con esto finalizamos la primera parte del artículo, pronto volveré con la seguna.

Espero que os haya gustado, Un Saludo!!

8 comentarios:

  1. Cosa fina!!

    Lo que siempre te digo: "Ahora me lo releeré 48237484 veces!!"

    Lo único que veo mal de todo es el dominio... grrrr

    ResponderEliminar
  2. Muchas gracias señores!!

    No es tan difícil como parece.. :)

    ResponderEliminar
  3. muy bueno ,te hago una referencia a tu articulo en HACKPLAYERS
    un saludo

    ResponderEliminar
  4. Respuestas
    1. Me alegro que te guste! ;)

      Es una lástima no publicar más a menudo, pero se va haciendo lo que se puede :D

      Saludos!!

      Eliminar
  5. Hace poco que encontre tu blog y es genial, ya tienes otro seguidor asegurado.

    ResponderEliminar
    Respuestas
    1. Me alegro que te guste ;)

      Saludos!!

      Eliminar