Ir al contenido principal

Iniciación a la técnica de ROP

Explotacion usando el controlador de Excepciones SEH con r2 y x32dbg


Buenas noches a todos, (00:57)

Este viernes me he puesto al día con el tute de @RicardoNarvaja de CrackLatinos, el cual planteaba un ejercicio que para resolverlo hay que hacer uso del manejador de excepciones y ver como podemos explotar un programa haciendo uso del mismo.


El binario que vamos a analizar es ABOS2 (el antiguo), con MD5 = 1efa6d3f257f9a98ac65529edc0820b4, ya que Ricardo lo ha actualizado para que al alcanzar los símbolos coincidan con el binario y sea mas fácil su análisis.

Para comprobarlo podemos hacer uso de la herramienta (rahash2) del set de tools que vienen con radare2.



  • rahash2 -a md5  ABO2_VS_2017.exe

Bueno como siempre hacemos debemos de tener una idea general acerca del binario, para ello ejecutamos el comando:

  • rabin2 -I ABO2_VS_2017.exe
                              

Vemos que es un binario de x86, como la mayoría de los que hemos ido analizando en este blog.

Abrimos el programa con Radare2 y analizamos un poco el mismo para ver que tiene:


  • r2  ABO2_VS_2017.exe
  • aaa --> analizamos el programa 
  • afl --> listamos las funciones del binario
  • idp ABO2_VS_2017.pdb --> Cargamos los símbolos del binario
  • s main --> nos vamos a la dirección de la memoria virtual del main()
De todas maneras en una entrada del blog anterior (comandos básicos con Radare2), podéis echarle un vistazo mejor a la explicaciones de los comandos.

Tras situarnos en la primera instrucción del main(), nos vamos al modo PANELS con:

  • V!


                                  


Como vemos tenemos una llamada a messageboxA(), una llamada a gets() y una llamada a exit()
De las cuales la función vulnerable es gets() , ya que lee la cadena hasta que encuentre un final de cadena.

Esto puede provocar que se produzca un Buffer Overflow, ya que nuestro compilador reserva un espacio determinado para la variable (el que le indicamos + extra(opcional)) cuando se compila y genera el ejecutable, y si nosotros guardamos en esa variable un tamaño mayor de datos del reservado, se produce el "overflow".

Para que sea mas fácil su entendimiento hacemos lo siguiente:

  • Re-nombramos la variable "s" por "buffer"
  • Mostramos el desensamblado de la función main() con la variable cambiada
  • Miramos el "stack frame" de la función main() y nos damos cuenta que la variable buffer se encuentra a 0x400 del horizonte (en radare EBP)
                               



Vale sabemos que si machacamos ese tamaño reservado por le compilador para la variable Buffer, mas el tamaño del EBP guardado (4 bytes), lo siguiente que modificaríamos sería el "return address", por lo tanto podríamos saltar a la dirección donde queremos del programa.

Todo esto dando por supuesto que no tenemos ni NX canary, ni DEP. (que ya lo hemos comprobado con la herramienta rabin2).

Un detalle a destacar es que, tras desensamblar la función main(), vemos que hay una llamada a exit(), por lo tanto si producimos un buffer overflow en el gets() no llegaremos a redirigir el flujo ya que nunca llegaremos a la instrucción ret de la función.

Por lo que hay que buscar una alternativa, en este caso será hacer uso del controlador de excepciones SEH, el cual sobrescribiremos y saltaremos produciendo una excepción en la función gets(). Para ello la protección Safe-SEH debe de estar deshabilitada, podemos comprobarlo con este powershell incrustado en el tute.

El SEH es una estructura que esta compuesta por los siguientes campos:
Donde el primer campo apunta al siguiente controlador de la lista, y el segundo apunta a la dirección encargada de gestionar esa excepción.La posición del controlador de excepciones en el stack es la siguiente:

Por lo tanto, hemos de introducir un valor bastante grande en con el gets() para poder machacar el valor de SEH. Para ello nos vamos a la primera instrucción de nuestra función donde se ejecuta el gets() y vemos el controlador de excepciones donde se encuentra:



Vemos que tenemos el primero en la dirección 0x18FF78 y que el código que se encarga de gestionar la excepción comienza en la dirección 0x401B70.

Tal y como hemos visto en teoría, en nuestro stack debe de aparecer en la dirección 0x18FF78 la dirección del siguiente controlador de excepciones (en este caso 0x18FFC4) y justo debajo en la dirección 0x18FF7C, debe de estar la dirección 0x401B70, encargada de gestionar la excepción.



Para ver en que momento machacamos el puntero SEH, podemos hacer lo que recomendó el maestro Ricardo, introducir una input aleatoria y detectar la longitud necesaria para sobrescribir la dirección 0x18FF7C , aunque si sabemos que el buffer empieza en EBP-0x400 = 0x18FB40.

La diferencia es 0x43C = 1084, por lo que vamos a introducir una entrada con python con 1084 "A" y sobrescribiendo la dirección que gestiona la excepción con "BBBB", tal y como muestra la siguiente imagen:

Vemos que se ha sobrescrito, aun así para que se produzca la excepción debemos de concatenar posteriormente un mayor número de caracteres, hasta que se produzca la excepción, y esta haga al programa saltar a la dirección 0x42424242.

Tal y como vemos cuando salta la excepción si nos fijamos en el stack, podemos fijarnos que en la tercera posición del stack se encuentra la dirección que apuntaba al siguiente elemento en la lista de SEH, (definido en la posición 0x18FF78). Esto es una característica del controlador de excepciones sobre x86.

Por lo tanto si encontramos en nuestro binario alguna dirección en la que tengamos esta secuencia de comandos (POP X, POP X , RET). Podemos controlar el flujo de nuestro programa, si en vez de sobrescribir el SEH con "BBBB"  apuntamos a la dirección donde se ejecutan esas instrucciones, ya que saltaríamos a la dirección que indiquemos cuando sobrescribimos en el stack la direccion 0x18FF78 (next SEH pointer).

Por ejemplo en la dirección 0x402A1D tenemos ese grupo de instrucciones, por lo que podemos probar que ocurre con nuestro programa cuando introducimos el siguiente input:


 1080* "A" (relleno) + "\x90\x90\x90\x90" (puntero next SEH que es el código que se ejecutará tras el POP, POP, ret) + "\x1D\x2A\x40\x00" (dirección de las instrucciones POP, POP ,ret en nuestro binario)

Para introducir este input, es necesario hacer uso de un lenguaje de scripting como python y Popen/Pcommunicate para introducir comandos no imprimirles.

Tras ejecutar el programa y "attachearnos" a este usando x32dbg, podemos ver como ser produce la excepción y saltamos a la dirección de nuestro next SEH pointer, ejecutando el código en hexadecimal que hemos introducido 0x90909090 (nop, nop.nop,nop). Junto con el resto de caracteres añadidos posteriormente que serían (\x1D\x2A\x40\x00 + \x43\x43....)


Vale una vez tenemos el flujo controlado, ya podemos hacer lo que queramos, en el ejercicio nos pide que ejecutemos una calculadora, por lo tanto introducimos la shellcode de una de las entradas anteriores, y  añadimos a la misma un exitprocess() para que salgamos del controlador de excepciones. Ya que sino, al terminar nuetra shellcode nuestro binario "peta" y esto provoca una excepción, que llamaría a su vez al controlador de excepciones entrando en un bucle infinito... (vamos que pasaríamos mas tiempo aquí que un político en un club de alterne, y ejecutaríamos infinitas calculadoras :) :P)

Nuestro código en python quedaría de la siguiente manera:




En este último código, hemos sustituido las 4 instrucciones nop que teníamos, por un salto de 6 instrucciones (\xeb\x06) + 2 nop para que este alienado con 4 (\x90\x90). Así saltamos a la primera instrucción justo después de la dirección del (pop, pop ,ret).



Un saludo

Krilin4






Comentarios

Entradas populares de este blog

Hack the Box Eat the cake!

Buenas de nuevo, retomo esto en un "ratillo" que he sacado para ir dándole un poco de contenido al blog.

Hoy nos ponemos con el resto Eat the cake! de HTB, ya que el otro día me calenté e hice un par de retos para ver lo oxidado que estaba... La verdad que bastante! 😑


El fichero os lo podéis bajar directamente de la página, cuyo SHA256:bd2efc7a1b23885d88d401b2a1fa1d4b307f6efcd76ee0a7d9486f0a8b06e586

Bueno vemos a ponernos manos a las obra, es un ejecutable por lo tanto nos iremos a nuestra máquina Windows que tenemos preparada para este tipo de retos, y abrimos el archivo con el software PEiD para ver si esta empaquetado/ofuscado, pero vamos que ya os digo que sí.



Vemos que PEiD nos dice que esta empaquetada con UPX 0.89.6 -1.02 / 1.05 - 2.90 --> Markus & Laszlo.
Intentamos desempaquetar la muestra, usando UPX directamente con "upx -d" y tras desempaquetarlo, comprobamos si se  ha hecho de manera correcta, procediendo a su ejecución y esperando a que sea co…

WinDBG- Diseño de ShellCodes

Buenas a  todos,

En este pequeño tutorial, voy a intentar explicar y mostrar con ejemplos como crear shellcode tanto en binarios de x86, y posteriormente crearé una entrada para ejemplos en binarios en x64.

Este tutorial esta basado en la parte 6 de los tutoriales  de Ricardo Narvaja de uso de herramientas de exploiting gratuitas y el tutorial de desarrollo de malware de ZeroPad, así que si os gusta las gracias a ellos.

Partimos de una shellcode que vamos a detallar, para explicar como funciona, y los componentes de la misma. Para ello hemos creado un binario donde se ejecuta únicamente esta shellcode para que nos sea mas fácil a la hora de analizarla.

winexec_calc_shellcode =b'\x33\xd2\x52\x68\x63\x61\x6c\x63\x89\xe6\x52\x56\x64\x8b\x72\x30\x8b\x76\x0c\x8b\x76\x0c\xad\x8b\x30\x8b\x7e\x18\x8b\x5f\x3c\x8b\x5c\x1f\x78\x8b\x74\x1f\x20\x01\xfe\x8b\x4c\x1f\x24\x01\xf9\x0f\xb7\x2c\x51\x42\xad\x81\x3c\x07\x57\x69\x6e\x45\x75\xf1\x8b\x74\x1f\x1c\x01\xfe\x03\x3c\xae\xff\xd7'


La shellcod…

Reversing Write-up Hatred (Bitup19)

Buenas a todos,

Después de un fin de semana intenso peleándome con C++ un poco ( ya veréis el churro de código que he hecho), me he decidido hacer un write-up de como resolví el reto de Hatred, con la compañía de un "figura" de CrackLatinos @bym24v..., bueno sentimentalismos atrás, vamos al turrón!

Comenzamos abriendo el binario y comprobamos que un un binario de x64( por lo tanto, necesitamos ejecutarlo en un SO de x64), seguidamente, vemos que al ejecutarse el binario, se nos cierra automáticamente sin mostrar nada..... (SOSPECHOCHO!)

Lo abrimos con IDA para ver porque se sale y comenzamos a "debuggearlo", lo primero que hacemos es buscar la función main() y re-nombrarla para verlo mas bonito con IDA.



Una vez ya la tenemos localizada, nos metemos dentro de la función, y vemos que nada mas comenzar hace una llamada a IsDebbugerPresent() (esta función nos devuelve eax = 0x1 cuando estamos "debugueando" y eax= 0x0 cuando no). Vemos que independientemente …