STACK-FOUR amd64

Este nivel explica lo que puede pasar si tenemos la capacidad de sobrescribir el puntero de instrucción rip. Esto es lo que se considera un Buffer Overflow estandar.

UTILIZANDO EL DEPURADOR

Como en todos los anteriores, lo primero es utilizar rabin2 para obtener más información del binario:

stack-four. rabin2

Después lo podemos abrir en nuestro depurador, analizar todo y comprobar las funciones para ver qué estamos buscando:

stack-four. afl

Vemos que el binario utiliza las funciones printf, gets, puts y exit. Todas ellas las conocemos de los ejemplos anteriores así que ya sabemos que gets es explotable.

Además de eso, vemos que hay llamadas a tres funciones interesantes:

  • sym.complete_level

stack-four. complete_level

Como vemos, la función complete_level no tiene más que una llamada a puts() que no encierra ningún problema a estas alturas.

  • sym.start_level

stack-four. start_level

Esta función ya tiene un funcionamiento más complejo. Cuando analicemos main, veremos start_level en profundidad.

  • sym.main

stack-four. main

La función main no encierra ninguna complejidad. Una llamada a puts para el BANNER y después llama directamente a la función start_level. Por este motivo, se debe analizar en profundidad la función start_level.

PREPARANDO EL EXPLOIT

Si nos fijamos en la ejecución principal de la función, podemos entender un poco mejor lo que hace:

Como vemos, la función hace varias cosas:

  • Llamada a gets para llenar el buffer en [rbp - 0x50].

  • Justo después coge el valor de [rbp + 0x8] y lo mete en [rbp - 0x8]

  • Por ultimo utiliza el valor de [rbp - 0x8] en un printf junto con una string que dice algo referente a la dirección de retorno.

si analizamos el stack justo después de la llamada a gets, podremos averiguar que es lo que se almacena en [rbp - 0x8]:

  • Vamos a preparar una prueba de concepto:

  • La introducimos en el debugger con rarun2:

  • Comprobamos el stack justo después de gets():

Como podemos ver, al llenar el stack con datos, hemos alcanzado la dirección con offset [rbp + 0x4]. Si analizamos la información de [rbp + 0x8] podemos ver que tiene almacenada una dirección de memoria (Little Endian) que es 0x0040068d Si vemos el desensamblado de la función main, vemos que esta dirección de memoria es la dirección siguiente a la de call start_level. Esto significa que hemos encontrado la dirección de retorno.

Ahora, lo único que nos queda es sobrescribir la dirección de retorno con una dirección que nos lleve a la función completelevel. En este caso, la primera dirección de complete_level es: 0x0040061d.

EXPLOTANDO LA VULNERABILIDAD

A continuación podemos retocar nuestro exploit para que cumpla con nuestros requisitos:

Hemos conseguido sobrescribir la dirección de retorno y modificar el flujo del binario.

CÓDIGO FUENTE

Después de comprobar que el exploit funciona podemos analizar el código fuente para comprobar qué hacía el binario exactamente.

Última actualización

¿Te fue útil?