133 lines
14 KiB
Markdown
133 lines
14 KiB
Markdown
# Buffer Overflow
|
||
|
||
Índice:
|
||
- [Buffer Overflow](#buffer-overflow)
|
||
- [8.1. Introducción al Buffer Overflow](#81-introducción-al-buffer-overflow)
|
||
- [8.2. Creación de un laboratiorio de pruebas e instalación de Immunity Debugger](#82-creación-de-un-laboratiorio-de-pruebas-e-instalación-de-immunity-debugger)
|
||
- [8.3. Fase inicial de Fuzzing y tomando el control de registro EIP](#83-fase-inicial-de-fuzzing-y-tomando-el-control-de-registro-eip)
|
||
- [8.4. Asignación de espacio depara el Shellcode](#84-asignación-de-espacio-depara-el-shellcode)
|
||
- [8.5. Generación de Bytearrays y detección de badchars](#85-generación-de-bytearrays-y-detección-de-badchars)
|
||
- [8.6. Búsqueda de OpCodes para entrar al ESP y cargar nuestro ShellCode](#86-búsqueda-de-opcodes-para-entrar-al-esp-y-cargar-nuestro-shellcode)
|
||
- [8.7. Uso de NOPs, desplazamientos en pila e interpretación del Shellcode para lograr RCE](#87-uso-de-nops-desplazamientos-en-pila-e-interpretación-del-shellcode-para-lograr-rce)
|
||
- [8.8. Modificación del Shellcode para controlar el comando que se desea ejecutar](#88-modificación-del-shellcode-para-controlar-el-comando-que-se-desea-ejecutar)
|
||
- [8.9. Explotando un nuevo binario para reforzar lo aprendido](#89-explotando-un-nuevo-binario-para-reforzar-lo-aprendido)
|
||
- [8.10. Funcionamiento y creación manual de Shellcodes](#810-funcionamiento-y-creación-manual-de-shellcodes)
|
||
|
||
|
||
## 8.1. Introducción al Buffer Overflow
|
||
|
||
El buffer overflow (desbordamiento de búfer) es una vulnerabilidad común en software que puede permitir a un atacante ejecutar código malicioso o tomar control de un sistema comprometido.
|
||
|
||
Esta vulnerabilidad se produce cuando un programa intenta almacenar más datos en un búfer (zona de memoria temporal para almacenamiento de datos) de lo que se había previsto, y al exceder la capacidad del búfer, los datos adicionales se escriben en otras zonas de memoria adyacentes.
|
||
|
||
Esto puede permitir que un atacante escriba código malicioso en estas zonas de memoria y sobrescriba otros datos críticos del sistema, como la dirección de retorno de una función o la dirección de memoria donde se almacena una variable, permitiendo al atacante tomar el control del flujo del programa.
|
||
|
||
Los impactos de un buffer overflow pueden ser graves, ya que un atacante puede aprovechar esta vulnerabilidad para obtener información confidencial, robar datos o incluso tomar el control completo del sistema. Si los atacantes disponen del conocimiento necesario, pueden incluso conseguir ejecutar comandos maliciosos en el sistema comprometido.
|
||
|
||
En las siguientes clases, se verán ejemplos concretos de explotación de buffer overflow en sistemas Windows, lo que ayudará a comprender cómo los atacantes pueden aprovechar esta vulnerabilidad y cómo se pueden tomar medidas preventivas para proteger los sistemas y las aplicaciones.
|
||
|
||
|
||
## 8.2. Creación de un laboratiorio de pruebas e instalación de Immunity Debugger
|
||
|
||
En esta clase, estaremos configurando todo el laboratorio para poder practicar nuestros primeros casos de Buffer Overflow.
|
||
|
||
Para ello, necesitarás instalar las siguientes cosas:
|
||
|
||
- Windows 7 Home Premium: https://windows-7-home-premium.uptodown.com/windows
|
||
- Immunity Debugger: https://immunityinc.com/products/debugger/
|
||
- mona.py: https://raw.githubusercontent.com/corelan/mona/master/mona.py
|
||
- SLMail: https://slmail.software.informer.com/download/
|
||
|
||
Asimismo, recordad que es muy importante deshabilitar el DEP (Data Execution Prevention), de lo contrario los Buffer Overflow que estaremos haciendo no funcionarán.
|
||
|
||
DEP (Data Execution Prevention) es una medida de seguridad que se utiliza para prevenir la ejecución de código malicioso en sistemas comprometidos a través de un buffer overflow.
|
||
|
||
DEP trabaja marcando ciertas áreas de memoria como “no ejecutables“, lo que significa que cualquier intento de ejecutar código en esas áreas de memoria será bloqueado y se producirá una excepción.
|
||
|
||
Esto es especialmente útil para prevenir ataques de buffer overflow que intentan aprovecharse de la ejecución de código en zonas de memoria vulnerables. Al marcar estas zonas de memoria como “no ejecutables”, DEP puede prevenir que el código malicioso se ejecute y proteger el sistema de posibles daños. Aún así, esto puede no ser suficiente para impedir que el atacante logre inyectar sus instrucciones maliciosas.
|
||
|
||
|
||
## 8.3. Fase inicial de Fuzzing y tomando el control de registro EIP
|
||
|
||
En la fase inicial de explotación de un buffer overflow, una de las primeras tareas es averiguar los límites del programa objetivo. Esto se hace probando a introducir más caracteres de los debidos en diferentes campos de entrada del programa, como una cadena de texto o un archivo, hasta que se detecte que la aplicación se corrompe o falla.
|
||
|
||
Una vez que se encuentra el límite del campo de entrada, el siguiente paso es averiguar el offset, que corresponde al número exacto de caracteres que se deben introducir para provocar una corrupción en el programa y, por lo tanto, para sobrescribir el valor del registro EIP.
|
||
|
||
El registro EIP (Extended Instruction Pointer) es un registro de la CPU que apunta a la dirección de memoria donde se encuentra la siguiente instrucción que se va a ejecutar. En un buffer overflow exitoso, el valor del registro EIP se sobrescribe con una dirección controlada por el atacante, lo que permite ejecutar código malicioso en lugar del código original del programa.
|
||
|
||
Por lo tanto, el objetivo de averiguar el offset es determinar el número exacto de caracteres que se deben introducir en el campo de entrada para sobrescribir el valor del registro EIP y apuntar a la dirección de memoria controlada por el atacante. Una vez que se conoce el offset, el atacante puede diseñar un exploit personalizado para el programa objetivo que permita tomar control del registro EIP y ejecutar código malicioso.
|
||
|
||
|
||
## 8.4. Asignación de espacio depara el Shellcode
|
||
|
||
Una vez que se ha encontrado el offset y se ha sobrescrito el valor del registro EIP en un buffer overflow, el siguiente paso es identificar en qué parte de la memoria se están representando los caracteres introducidos en el campo de entrada.
|
||
|
||
Después de sobrescribir el valor del registro EIP, cualquier carácter adicional que introduzcamos en el campo de entrada, veremos desde Immunity Debugger que en este caso particular estos estarán representados al comienzo de la pila (stack) en el registro ESP (Extended Stack Pointer). El ESP (Extended Stack Pointer) es un registro de la CPU que se utiliza para manejar la pila (stack) en un programa. La pila es una zona de memoria temporal que se utiliza para almacenar valores y direcciones de retorno de las funciones a medida que se van llamando en el programa.
|
||
|
||
Una vez que se ha identificado la ubicación de los caracteres en la memoria, la idea principal en este punto es introducir un shellcode en esa ubicación, que son instrucciones de bajo nivel las cuales en este caso corresponderán a una instrucción maliciosa.
|
||
|
||
El shellcode se introduce en la pila y se coloca en la misma dirección de memoria donde se colocaron los caracteres sobrescritos. En otras palabras, se aprovecha el desbordamiento del búfer para ejecutar el shellcode malicioso y tomar control del sistema.
|
||
|
||
Es importante tener en cuenta que el shellcode debe ser diseñado cuidadosamente para evitar que se detecte como un programa malicioso, y debe ser compatible con la arquitectura de la CPU y el sistema operativo que se está atacando.
|
||
|
||
En resumen, la asignación de espacio para el shellcode implica identificar la ubicación en la memoria donde se colocaron los caracteres sobrescritos en el buffer overflow y colocar allí el shellcode malicioso. Sin embargo, no todos los caracteres del shellcode pueden ser interpretados. En la siguiente clase veremos cómo detectar estos badchars y cómo generar un shellcode que no disponga de estos caracteres.
|
||
|
||
|
||
## 8.5. Generación de Bytearrays y detección de badchars
|
||
|
||
En la generación de nuestro shellcode malicioso para la explotación del buffer overflow, es posible que algunos caracteres no sean interpretados correctamente por el programa objetivo. Estos caracteres se conocen como “badchars” y pueden causar que el shellcode falle o que el programa objetivo se cierre inesperadamente.
|
||
|
||
Para evitar esto, es importante identificar y eliminar los badchars del shellcode. En esta clase, veremos cómo desde Immunity Debugger podremos aprovechar la funcionalidad Mona para generar diferentes bytearrays con casi todos los caracteres representados, y luego identificar los caracteres que el programa objetivo no logra interpretar.
|
||
|
||
Una vez identificados los badchars, se pueden descartar del shellcode final y generar un nuevo shellcode que no contenga estos caracteres. Para identificar los badchars, se pueden utilizar diferentes técnicas, como la introducción de diferentes bytearrays con caracteres hexadecimales consecutivos, que permiten identificar los caracteres que el programa objetivo no logra interpretar.
|
||
|
||
Estos caracteres irán representados en la pila (ESP), que será donde veremos qué caracteres son los que no están siendo representados, identificando así los badchars.
|
||
|
||
|
||
## 8.6. Búsqueda de OpCodes para entrar al ESP y cargar nuestro ShellCode
|
||
|
||
Una vez que se ha generado el shellcode malicioso y se han detectado los badchars, el siguiente paso es hacer que el flujo del programa entre en el shellcode para que sea interpretado. La idea es hacer que el registro EIP apunte a una dirección de memoria donde se aplique un opcode que realice un salto al registro ESP (JMP ESP), que es donde se encuentra el shellcode. Esto es así dado que de primeras no podemos hacer que el EIP apunte directamente a nuestro shellcode.
|
||
|
||
Para encontrar el opcode JMP ESP, se pueden utilizar diferentes herramientas, como mona.py, que permite buscar opcodes en módulos específicos de la memoria del programa objetivo. Una vez que se ha encontrado el opcode ‘JMP ESP‘, se puede sobrescribir el valor del registro EIP con la dirección de memoria donde se encuentra el opcode, lo que permitirá saltar al registro ESP y ejecutar el shellcode malicioso.
|
||
|
||
La búsqueda de opcodes para entrar al registro ESP y cargar el shellcode es una técnica utilizada para hacer que el flujo del programa entre en el shellcode para que sea interpretado. Se utiliza el opcode JMP ESP para saltar a la dirección de memoria del registro ESP, donde se encuentra el shellcode.
|
||
|
||
|
||
## 8.7. Uso de NOPs, desplazamientos en pila e interpretación del Shellcode para lograr RCE
|
||
|
||
Una vez que se ha encontrado la dirección del opcode que aplica el salto al registro ESP, es posible que el shellcode no sea interpretado correctamente debido a que su ejecución puede requerir más tiempo del que el procesador tiene disponible antes de continuar con la siguiente instrucción del programa.
|
||
|
||
Para solucionar este problema, se suelen utilizar técnicas como la introducción de NOPS (instrucciones de no operación) antes del shellcode en la pila. Los NOPS no realizan ninguna operación, pero permiten que el procesador tenga tiempo adicional para interpretar el shellcode antes de continuar con la siguiente instrucción del programa.
|
||
|
||
Otra técnica que se suele utilizar es el desplazamiento en la pila, que implica modificar el registro ESP para reservar espacio adicional para el shellcode y permitir que se ejecute sin problemas. Por ejemplo, se puede utilizar la instrucción “sub esp, 0x10” para desplazar el registro ESP 16 bytes hacia abajo en la pila y reservar espacio adicional para el shellcode.
|
||
|
||
Ya con esto, ¡habríamos conseguido vulnerar el sistema a través del Buffer Overflow!
|
||
|
||
|
||
## 8.8. Modificación del Shellcode para controlar el comando que se desea ejecutar
|
||
|
||
Además de los payloads que se han utilizado en las clases anteriores, también es posible utilizar payloads como “windows/exec” para cargar directamente el comando que se desea ejecutar en la variable CMD del payload. Esto permite crear un nuevo shellcode que, una vez interpretado, ejecutará directamente la instrucción deseada.
|
||
|
||
El payload “windows/exec” es un payload de Metasploit que permite ejecutar un comando arbitrario en la máquina objetivo. Este payload requiere que se especifique el comando a ejecutar a través de la variable CMD en el payload. Al generar el shellcode con msfvenom, se puede utilizar el parámetro “-p windows/exec CMD=<comando>” para especificar el comando que se desea ejecutar.
|
||
|
||
Una vez generado el shellcode con el comando deseado, se puede utilizar la técnica de buffer overflow para sobrescribir el registro EIP y hacer que el flujo del programa entre en el shellcode. Al interpretar el shellcode, se ejecutará directamente el comando especificado en la variable CMD.
|
||
|
||
|
||
## 8.9. Explotando un nuevo binario para reforzar lo aprendido
|
||
|
||
Con el objetivo de reforzar todo lo aprendido hasta ahora en esta sección, en esta clase vamos a intentar explotar otro Buffer Overflow. El procedimiento que aplicaremos será el mismo, aunque la fase inicial y la forma de entablar las conexiones en Python cambiarán un poco.
|
||
|
||
A continuación, se os comparte el enlace de descarga al software vulnerable que estaremos ejecutando:
|
||
|
||
- MiniShare: https://es.osdn.net/projects/sfnet_minishare/downloads/OldFiles/minishare-1.4.1.exe/
|
||
|
||
|
||
## 8.10. Funcionamiento y creación manual de Shellcodes
|
||
|
||
Los shellcodes son programas pequeños y altamente optimizados que se utilizan para explotar vulnerabilidades de seguridad y ejecutar código malicioso en una máquina objetivo. Los shellcodes suelen ser escritos en lenguaje ensamblador para garantizar una ejecución rápida y eficiente.
|
||
|
||
En esta clase, exploraremos cómo funcionan los shellcodes por detrás mediante la creación de algunos shellcodes manualmente. Por ejemplo, intentaremos crear un shellcode que muestre por consola el mensaje “Hola mundo” utilizando interrupciones del sistema. Asimismo, intentaremos aplicar una llamada a nivel de sistema para lograr ejecutar un comando deseado.
|
||
|
||
Una vez que se ha generado el compilado resultante, se puede utilizar el comando objdump para convertir el archivo binario generado en un shellcode que pueda ser utilizado en un Buffer Overflow.
|
||
|