Retos de iniciación al exploiting: Use-After-Free (UAF)
¡¡Hola compañeros!!
Como ya os contamos en el anterior post, hace algún tiempo que estamos aprendiendo explotación de binarios a través de la resolución de retos de CTFs.
Y por eso, estamos compartiendo con vosotros lo que vamos aprendiendo a través del desarrollo de una serie de pruebas o retos de iniciación al exploiting.
En esta ocasión, os traemos un reto sobre Use-After-Free (UAF). Estas vulnerabilidades se producen cuando un programa utiliza una dirección de memoria que ha sido liberada, pudiendo provocar una denegación de servicio, una filtración de memoria e incluso ejecución de código.
Al igual que el reto anterior, estará disponible en la plataforma TryHackMe y para acceder a la sala donde iremos subiendo los retos, tenéis que entrar en http://tryhackme.com/jr/securitygarage y uniros.
El código del binario es el siguiente:
El binario corre con socat en el Puerto 9000 de la máquina virtual de TryHackMe. Puedes conectarte al mismo con netcat:
nc <ip_instancia_try_hackme> 9000
Para la resolución de este reto, recomendamos su depuración en local para comprender cómo funciona la asignación de memoria.
Los siguientes recursos proporcionan información útil:
La solución al reto paso a paso se publicará en las próximas semanas en otra entrada del blog.
Para terminar, os dejamos la solución paso a paso del primer reto:
Como sabéis, el primer reto trataba sobre un buffer overflow simple. Una rápida inspección del código fuente permite encontrar la vulnerabilidad.
Podemos observar que se utiliza la función gets para leer la entrada del usuario. Como a la función se le pasa tan solo un puntero al array vuln[32], la función desconoce el tamaño del array, por tanto, no puede controlar que los datos de entrada quepan en el array pasado. Este comportamiento permite a un atacante escribir más allá del espacio asignado al array.
Una vez conectados al reto, se solicita al usuario una entrada, sin embargo, el programa compara la variable key y no la variable vuln, que es la que controlamos con un valor estático. Es por eso que obtendremos la respuesta Try harder...
Como ya conocemos que la función gets no limita el tamaño de entrada, probemos a sobreescribir el contenido adyacente al array vuln escribiendo una entrada mayor a 31 caracteres.
Como podemos ver, hemos sobreescrito la contraseña y ahora su valor es 41414141, es decir, “AAAA”, dado que “A” es 41 codificado como ASCII.
Ahora que sabemos que podemos sobreescribir el valor de la contraseña, tan solo necesitamos encontrar la posición exacta en la que se empieza a sobreescribir para escribir el valor que queramos. Para ello, crearemos un patrón cíclico. Pwntools (https://github.com/Gallopsled/pwntools) implementa la función cyclic(length), que permite generar este tipo de patrones.
Si probamos con el patrón generado.
Podemos observar como el valor escrito en la contraseña es 0x6161616c, como nos encontramos con un procesador little endian, se trata de 0x6c616161, es decir “aaal” decodificado como ASCII. Usando la función cyclic_find() podemos encontrar el punto de inserción.
Como se encuentra a 44 caracteres desde el inicio, tan solo tenemos que enviar 44 caracteres de relleno y luego el valor que queramos escribir en la variable.
Podemos hacer esto rápidamente con Pwntools.
Obteniendo así la bandera.
Esperamos que os haya gustado el reto.
¡Hasta pronto!