Cómo crear un bug de "Buffer Overflow" para crear su exploit y aprender
La ciberseguridad sigue su auge y la necesidad, y demanda, formativa es muy grande. La transversalidad de la ciberseguridad en cualquier paradigma tecnológico hace que su necesidad crezca y que la formación en perfiles de ciberseguridad sea muy demandada por las empresas. Esto daría para un artículo y hablar de esta necesidad y de las necesidades que tienen que cubrir las empresas, pero el artículo de hoy va más ligado a la parte técnica y al cómo crearse entornos para practicar lo estudiado, para practicar e interiorizar los conocimientos que uno va aprendiendo.
Una de las cosas más importantes es poder probar lo que uno estudia y para ello, el artículo de hoy, muestra cómo crearnos un pequeño escenario para estudiar y entender el Buffer Overflow. Hay muchos recursos en Internet que explican muy bien la teoría del desbordamiento de un buffer, es más, hay muchos que nos enseñan la teoría y nos dan ejemplos prácticos. Todo esto es fantástico y debemos valorarlo. No vale con ver cómo otros lo hacen en una clase. Debemos esforzarnos en entenderlo a bajo nivel, a pegarme con ello y una de esas posibilidades las obtengo cuando tengo que montarme el escenario.
Es como si quiero practicas técnicas de pivoting y me monto un laboratorio con máquinas virtuales, con diferentes redes y voy jugando con las diferentes formas de hacer pivoting. Esto me ayudará a profundizar mi aprendizaje, a encontrarme con problemas que el profesor no tuvo y a entender por qué suceden ciertas cosas y, sobre todo, interiorizar el conocimiento. Como digo esto nos daría para un artículo sobre la cultura del esfuerzo y la dedicación que es algo que en parte se está perdiendo y sustituyendo por la cultura de la inmediatez.
Figura 1: Cómo crear un bug de "Buffer Overflow" para crear su exploit y aprender
Una de las cosas más importantes es poder probar lo que uno estudia y para ello, el artículo de hoy, muestra cómo crearnos un pequeño escenario para estudiar y entender el Buffer Overflow. Hay muchos recursos en Internet que explican muy bien la teoría del desbordamiento de un buffer, es más, hay muchos que nos enseñan la teoría y nos dan ejemplos prácticos. Todo esto es fantástico y debemos valorarlo. No vale con ver cómo otros lo hacen en una clase. Debemos esforzarnos en entenderlo a bajo nivel, a pegarme con ello y una de esas posibilidades las obtengo cuando tengo que montarme el escenario.
Figura 2: Linux Exploiting. Un libro para aprender a explotar bugs y hacer exploits funcionales .de 0xword. |
El entrenamiento es algo fundamental y eso es lo que se verá en el Rooted Lab sobre entrenamiento a través de la resolución de escenarios. El próximo 9 de marzo un día completo de pentesting práctico a través de la resolución de escenarios de todo tipo.
Creando un programa en C
En primer lugar, vamos a crear una aplicación vulnerable a Buffer Overflow. El objetivo no es aprender en este post a detectar un buffer overflow y explotarlo, el objetivo es mostrar cómo se crea un escenario donde uno puede profundizar e ir entrando en materia sobre la teoría que nos puedan impartir. Lo primero es mostrar el código del programa en pseudocódigo y ver la idea que se tiene:
Este es el esqueleto de la aplicación. Se puede ver cómo podríamos ir jugando a mano introduciendo en la variable chrs posibles valores para ir detectando el desbordamiento. Por ejemplo, si ponemos “a pelo” el valor chrs = “aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa” podríamos llegar a detectar el bug con el buffer overflow de forma sencilla. Eso sí, lo tendríamos "hardcodeado", luego necesitaríamos introducirlo como un argumento de la aplicación o, si montamos un ejemplo más avanzado, a través de un socket.
El código para convertir el string a hexadecimal es sencillo, aunque en este caso lo que queremos es que la entrada a la aplicación ya venga en un string de hexadecimal, es decir, el string que recibirá la aplicación ya simula ser código hexadecimal, por lo que debe hacer nuestro código es convertirlo a hexadecimal que no dejará de ser un array de caracteres ‘unsigned’.
Probando y detectando overflow
Para este ejemplo sencillo y tras compilar el código, vamos a probar con un debbugger que el overflow está bien creado. Como debugger vamos a usar x64dbg, el cual es un debbugger Open Source. Para pasarle argumentos a nuestra aplicación vulnerable debemos hacerlo a través de la línea de comandos, como se puede ver en la siguiente imagen.
Se puede ver un gran número de 41414141… para identificar el offset del overflow deberíamos usar un patrón, creado con mona o con pattern_create, pero no es el objetivo del artículo enseñar el buffer overflow, si no el de crear un entorno y ver qué funciona. Ahora, al arrancar el debbugger vemos que hay un desbordamiento y se ve reflejado en el registro EIP, tal y como se puede ver en la imagen.
Para ver cómo controlamos el EIP y estamos “machacando” el valor de retorno de la función strcpy del código en Lenguaje C, podemos modificar la entrada y meter las X ‘A’ hasta llegar a la posición de la dirección de retorno de la función y le metemos 4 ‘B’. Se pueden ver reflejadas en la siguiente imagen, la aparición en el EIP de las 4 ‘B’ (\x42\x42\x42\x42).
Revisamos sobre nuestro código en el debugger si podemos encontrar instrucciones del tipo JMP ESP o CALL ESP para poder redirigir el flujo de la ejecución hacia nuestro código. Después tendremos que meter el número de NOPs que creamos necesario, así como el código ejecutable o shellcode que queremos lanzar.
Vamos ahora con la parte de la ejecución. En el buffer overflow básico el payload tendrá este aspecto:
Creando un programa en C
En primer lugar, vamos a crear una aplicación vulnerable a Buffer Overflow. El objetivo no es aprender en este post a detectar un buffer overflow y explotarlo, el objetivo es mostrar cómo se crea un escenario donde uno puede profundizar e ir entrando en materia sobre la teoría que nos puedan impartir. Lo primero es mostrar el código del programa en pseudocódigo y ver la idea que se tiene:
- El programa escrito en C recibirá un argumento (argv[1]) el cual será la ristra de bytes que queremos pasar a un buffer y provocar el buffer overflow.
- Una vez recibimos la entrada, la cual es un string la vamos a convertir en hexadecimal (eso sí, siguen siendo bytes).
- - Una vez que lo tenemos en hexadecimal aplicamos la función strcpy(b, buffer) dónde buffer almacena la ristra de bytes en hexadecimal de la entrada al programa y la variable b será el destino. La variable buffer será más grande que la variable b de modo que provocaremos el overflow al utilizar strcpy. La función strcpy es una función insegura, la cual no debe utilizarse en programación segura.
Figura 4: Un código en C con la función strcpy
Este es el esqueleto de la aplicación. Se puede ver cómo podríamos ir jugando a mano introduciendo en la variable chrs posibles valores para ir detectando el desbordamiento. Por ejemplo, si ponemos “a pelo” el valor chrs = “aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa” podríamos llegar a detectar el bug con el buffer overflow de forma sencilla. Eso sí, lo tendríamos "hardcodeado", luego necesitaríamos introducirlo como un argumento de la aplicación o, si montamos un ejemplo más avanzado, a través de un socket.
Figura 5: Ejemplo a través de un socket
El código para convertir el string a hexadecimal es sencillo, aunque en este caso lo que queremos es que la entrada a la aplicación ya venga en un string de hexadecimal, es decir, el string que recibirá la aplicación ya simula ser código hexadecimal, por lo que debe hacer nuestro código es convertirlo a hexadecimal que no dejará de ser un array de caracteres ‘unsigned’.
Probando y detectando overflow
Para este ejemplo sencillo y tras compilar el código, vamos a probar con un debbugger que el overflow está bien creado. Como debugger vamos a usar x64dbg, el cual es un debbugger Open Source. Para pasarle argumentos a nuestra aplicación vulnerable debemos hacerlo a través de la línea de comandos, como se puede ver en la siguiente imagen.
Figura 6: debugging overflow.exe con parámetro desbordante
Se puede ver un gran número de 41414141… para identificar el offset del overflow deberíamos usar un patrón, creado con mona o con pattern_create, pero no es el objetivo del artículo enseñar el buffer overflow, si no el de crear un entorno y ver qué funciona. Ahora, al arrancar el debbugger vemos que hay un desbordamiento y se ve reflejado en el registro EIP, tal y como se puede ver en la imagen.
Figura 7: Desbordamiento de Buffer en el debugger
Para ver cómo controlamos el EIP y estamos “machacando” el valor de retorno de la función strcpy del código en Lenguaje C, podemos modificar la entrada y meter las X ‘A’ hasta llegar a la posición de la dirección de retorno de la función y le metemos 4 ‘B’. Se pueden ver reflejadas en la siguiente imagen, la aparición en el EIP de las 4 ‘B’ (\x42\x42\x42\x42).
Figura 8: Localización de las 'B' en el EIP
Revisamos sobre nuestro código en el debugger si podemos encontrar instrucciones del tipo JMP ESP o CALL ESP para poder redirigir el flujo de la ejecución hacia nuestro código. Después tendremos que meter el número de NOPs que creamos necesario, así como el código ejecutable o shellcode que queremos lanzar.
Figura 9: Redirigir el retorno de strcpy a call ESP
Vamos ahora con la parte de la ejecución. En el buffer overflow básico el payload tendrá este aspecto:
- bytes basura +
- dirección RET modificada (apuntando a una instrucción de salto al ESP) +
- NOPs
- + Shellcode.
Figura 10: Ejecución del payload
Si revisamos el escenario, este código funciona perfectamente en un entorno Windows 10. Esto es debido a que DEP no viene por defecto para binarios de 32 bits. Además, se ha compilado sin meter protecciones en la pila.
Figura 11: Ejecución de calculadora al abrir el debugger
Como podéis ver, es un ejercicio interesante para hacer y poder aprender más sobre el buffer overflow creando una pequeña aplicación en la que uno tiene vulnerabilidades para poder aprender con ellas. Un escenario didáctico creado para la formación, y si queréis aprender más, os recomiendo el libro de "Linux Exploiting" de 0xWord que trae muchos de estos ejemplos didácticos.
Saludos,
Pablo González Pérez (@pablogonzalezpe), escritor de los libros "Metasploit para Pentesters: Gold Edition", "Hacking con Metasploit: Advanced Pentesting" "Hacking Windows", "Ethical Hacking", "Got Root", “Pentesting con Powershell (2ª Edición)”, "Pentesting con Kali Silver Edition" y de "Empire: Hacking Avanzado en el Red Team", Microsoft MVP en Seguridad y Security Researcher en el equipo de "Ideas Locas" de la unidad CDCO de Telefónica. Para consultas puedes usar el Buzón Público para contactar con Pablo González - Conseguir 100 Tempos Gratis en MyPublicInbox
Figura 12: Contactar con Pablo González |
No hay comentarios:
Publicar un comentario