Reversing

Introducción al Reversing con radare2 – 0x09 Ganando shell gracias a Brainfuck Parte I

Buenos días voy a dar solución al reto llamado bf del EBCTF 2013. A grandes rasgos como introducción al reto es un binario que contiene una función que es un interprete del lenguaje esotérico brainfuck. La parte de reversing de este reto es fundamental ya que la explotación se ve rápido.

Sabemos por el enunciado se que trata de un interprete de brainfuck por lo tanto sabemos que las operaciones que va a realizar según los caracteres que introduzcamos pedidos por la función fgets() son los siguientes:

Nuestros hitos principales ademas de reversear el código serán ver como poder conseguir shell ya que disponemos de una función sym.shell donde llama a system así que deberemos ver como mediante el interprete podemos controlar eip y así sobreescribir la dirección de retorno con la dirección de memoria de la función shell.
El interprete se encuentra en la función sym.bf_main por tanto solo deberemos realizar nuestra tarea de ingeniería inversa en esa función.

Ingeniería inversa de “>” y “.”

Comenzamos colocando un breakpoint justo en la dirección de memoria 0x080486b5 que corresponde antes de la llama a la función fgets().

Continuamos y escribimos para probar los siguientes caracteres:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
Cuando llama a la función strlen devolverá justo la longitud de nuestros caracteres y tomara el salto ya que no es igual a la longitud.

Una vez realiza el salto movería el valor de nuestro carácter > siendo en hexadecimal 0x3e a ebp-0x18.

Finalmente recupera el valor 0x3e y se lo resta a 0x2b para compararlo con 0x32. Si realizamos la resta nos da 0x13 por lo tanto no saltará y en la instrucción mov eax, dword [eax*4 + 0x8048bac] realizará una operación aritmética haciendo que eax valga una dirección de memoria del código de la propia función saltando. Vemos donde salta a 0x080487fe.

En estas instrucciones lo que realiza es mover el valor 2 a direcciones del stack empezando por:

Si seguimos ejecutando nos damos cuenta que ahora cuando sale de la función strlen el registro ebx vale uno así que eso quiere decir que va incrementandose uno mediante vamos iterando en los caracteres introducidos anteriormente.

Al dar la segunda vuelta vemos que entra de nuevo en el case del switch para el carácter > en la dirección de memoria 0x080487fe y nuestro registro ecx ahora vale 0x20 que sumará a la dirección del stack 0xbfc554d0 en vuestro caso será otra jeje. Dará como valor ahora 0xbfc554d8.

Antes de continuar quiero tener controlado el stack desde ebp hasta esp, por lo tanto si introducimos el comando px 1248 @esp vemos toda la pila justo hasta la dirección de retorno, justo al lado de ebp. Es interesante tener esto controlado porque tendremos que realizar más adelante nuestros cálculos ya que el objetivo es sobreescribir esta dirección controlando eip para poder ganar shell.

Si realizamos bastantes interacciones nos damos cuenta que siempre jmp eax saltará a la misma dirección de memoria 0x080487fe justo cuando termine nuestro carácter > y recordar que introdujimos unos cuantos jeje.

Si vemos en el stack nuestro “02” esta en el volcado hexadecimal cada 8 bytes.

Una vez ya hace todos los “>” realiza el “.” entrando en el case 7 y al final lo que hace es mover el valor “07” en el incremento de la dirección de memoria del stack.

Si analizamos el stack estabamos en lo cierto hay 34 “02” cada 8 bytes empezando por arriba en la pila y un “07” a continuación del último.

Por lo tanto hemos entendido hasta ahora lo siguiente:

  • Almacena cada 8 bytes el valor “02” en la pila correspondiendo a que introdujimos “>”
  • Almacena cada 8 bytes el valor “07” en la pila correspondiendo a que introdujimos “.”, en este caso como solo escribimos uno pues solo ejecutara este case.

Una vez realizado esto salta al case default.

Y va a estar comprobando si el puntero sea igual a “07”, si realizamos la primera iteración va a comprobar y va a dar “02” correspondiendo al primer puntero donde se movió ese valor con el carácter “>”. El registro eax vale “02″

Si realizamos bastantes iteraciones nos damos cuenta de que va comprobando uno a uno, puntero a puntero de que el valor sea igual a “07” pero es “02” porque empieza desde el primero de todos. Así que seguimos ejecutando justo cuando la comparación sea igual para ver lo siguiente que realizara. Ahí vemos nuestro eax que vale “07” jeje.

Vemos que salta ahora a una dirección de memoria diferente correspondiendo al final a una función printf y si vemos como funciona brainfuck el “.” significa que imprime por pantalla cierto valor de la pila.

En esta instrucción eax vale 0x23.

Cuando ejecuta la instrucción lea, edx vale 0x8c y seguidamente mueve el contenido de ebp-0x44 a eax que contiene la dirección de memoria del primer puntero donde se escribió para luego sumarle 0x8c a esa dirección quedando 0xbfc5595c y si vemos lo que ahí allí tenemos un 0x77 jeje

Por tanto imprimirá ese valor. Si analizamos el stack nos interesa visualizar la dirección de retorno así que solo tenemos que calcular la diferencia para añadir mas desplazamientos del puntero con “>”.

Si ejecutamos px 1248 @esp no hay tanta diferencia hasta llegar a nuestro return address jeje

Nuestra dirección de retorno corresponde justo a la dirección que tiene q saber donde retornar justo cuando termine de ejecutar la función sym.bf_main

Ahora si ejecutamos nuestro binario vemos que estábamos en lo cierto realizando simplemente ingeniería inversa.

En la siguiente parte reversearemos “-“ y daremos solución final para ganar shell. Un saludo naivenom.

4 comentarios en “Introducción al Reversing con radare2 – 0x09 Ganando shell gracias a Brainfuck Parte I

  1. Hola, ando muy enganchada a las entradas de reversing. En esta última se ve muy bien el paso a paso.
    Gracias por el trabajo, muy útil para los que estamos aprendiendo.
    Un saludo!

Deja un comentario

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

Los datos introducidos se guardarán en nuestra base de datos como parte del comentario publicado, como se indica en la política de privacidad.