Explotación de Buffer Overflow (desbordamiento de búfer): explicación y ejemplo

   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.

    Para ello, necesitarás instalar las siguientes cosas:
    





Fase inicial de Fuzzing y tomando el control del 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.

    Descargamos mona y cambiamos e archivo desde consola de txt a py para meterlo en la siguiente carpeta:



    Nos encontramos frente a la siguiente direccion IP 


    Vemos que tiene los puertos 9999 y 10000 abiertos. Si fuzeamos encontraremos el binario y con un servidor en python nos lo traemos a immunity debugger para analizarlo.


    Nos traeremos el binario al Inmunity debuger


    Antes de hacer fuzzing, en Windows  vamos a abrir como administrador el Immunity Debugger para adjuntarnos al proceso del Brainpan.exe y ejecutamos el binario y vemos que levanta el puerto 9999:


    A continuación, necesitamos crear un simple fuzzer que envíe ‘A’ contra el target para hacerlo petar:


    Se ejecuta el fuzzer haciendo que la aplicación fallé y que el registro EIP quede sobreescrito con todo A (0x41):



    El objetivo es conocer la longitud máxima de entrada justo antes de sobreescribir el registro EIP. Para ello, nos ayudaremos de las herramientas: pattern_create y pattern_offset.

    Pattern_create permite crear un string al azar donde no se repite ninguna secuencia de caracteres. Se usa para calcular el punto exacto donde quedará el offset cuando el programa peta, y ponemos 600 que es el numero de bits con el que peta


Pegamos su salida en un exploit  en la variable payload 


    Le tenemos que indicar a mona la cantidad de bytes que necesita el programa para petar


    Una vez pegada la salida en el exploit lo ejecutamos. PERO ANTES HAY QUE VOLVER A EJECUTAR EL BINARIO puesto que al petar este en pause



    Acabamos de obtener el valor del EIP, es decir lo que corrompe el binario
    
    Con pattern_offset creamos el valor máximo del input previo a la sobreescritura del EIP, es decir 514 "A" que le tengo que pasar para que luego lo que ponga lo sobrescriba en el EIP


    Así que modificamos nuevamente le exploit declarando  el offset y en el valor retn, ponemos 4 B para ver que funciona correctamente, por lo tanto al ver el registro EIP con valor 42424242 sabremos que a funcionado, puesto que  42424242 es lo que sobreescribiria 


    Reanudamos el binario y ejecutamos el expoit



    Y peta, ahora podemos tratar donde se representa los caracteres para que podamos lanzar comandos 

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. 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.


    Antes de nada es importante que creemos una carpeta donde guardar todos los archivos




    Nos lo crea en la ruta, pero vamos a quitar el null byte:


    Ya no nos sale el \\x00,


     Nos lo traemos a nuestra maquina atacante y lo incluimos en el exploit 


Lo ejecutamos de nuevo y:



Copiamos el ESP y podemos ver cuales faltan con mona. 
Pero si no queremos hacerlo manual podemos hacerlo con mona compare en el caso de que hubiera eliminarlo



Y vemos que no hay caracteres que no le molen

    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.

    Lo que nos interesa es identificar una instrucción de salto JMP ESP que se corresponde con un FFE4, entonces introducimos esa búsqueda mediante mona:

    Asi que buscamos cualquier direccion que apunte pero no contenga los badchars que hemos detectado


    Como se puede observar, se encuentra esa instrucción en la dirección de memoria 0x31171213

    Yendo a esa dirección, identificamos efectivamente la instrucción que buscábamos e indicamos que queremos ir a esa dirección que indicamos 


    Vemos que en el opcode  la dirección FFE4 corresponde a junpESP y hacemos el Breakpoint


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.
    
    Vamos a intentar que el Shellcode haga una RCE y gracias a la funcion EXITFUNC=thread el programa ni se corrompe ni se para 


    Pues bien nuestras instrucciones son complejas y puede que tarde mas en  ejecutarlas de las que el procesador tiene disponible y se pone en un espacio de descanso de forma que ya hay tiempo suficiente para que luego el procesador los interprete mediante NOPs. Eso o mediante un despazamiento de la pila 

    Asi que modificamos el exploit y le metemos NOPS, dando un espacio en que no se hace nada y el procesador ya tiene tiempo a procesas la instrucción, le metemos 16 NOP's justo antes de que entre el shellcode (retn)
    
    Ademas de sustituir las ‘B’, esto es, en el orden contrario al que obtenemos de Immunity. En este caso sería: /xf3/x12/x17/x31 (padding) decrementando el valor del puntro de la pila


    Lanzamos el exploit y estamos dentro 


No hay comentarios:

Publicar un comentario