Windows Exploitation Challenge - Blue Frost Security 2022 | ||||||||||||
|
||||||||||||
Hola y bienvenidos a todos los lectores. ProteccionesLas protecciones de un binario son aplicadas para evitar que una posible explotación sea de manera trivial, aumentando la dificultad de explotación. Utilizamos la herramienta de winhecksec.exe, el cual nos muestra que el binario tiene habilitado la protección ASLR, DEP y GS que no se visualiza, pero reversando se puede validar.
AnálisisLo primero es lo primero, así que vamos a ejecutar el binario y vemos que levanta un servicio socket en algún puerto. Utilizamos Process Hacker y en la pestaña Network filtramos por el nombre del binario y vemos que el servicio corre en el 31415. Esta es la manera mas fácil de identificar el puerto. Otra forma seria reversando y ver los parámetros de la función listen(), pero para que nos vamos a complicar. Ya con esto creamos la primera estructura del script para que se comunique con el servicio. Este lo utilizaremos mas adelante en el análisis dinámico, por ahora vamos a ir reconociendo el flujo de forma estática. Viendo el código identificamos primeramente la función main(), donde aquí se ejecutan las siguientes acciones que levantan el servicio y realiza algunas comprobaciones de los datos enviados. Lo mas importante de aquí es cmp_msg_hello() que se encarga de comparar los bytes recibidos con una constante llamada “Hello”, si es así sigue el camino correcto al send() para responder con un “Hi” mediante la conexión socket y poder llegar a la función packet_filter(). Ahora vemos las rutinas de packet_filter(), es aquí donde se encuentran las vulnerabilidades y donde hay que pensar. Cuando entra a la función se ejecuta una especie de memset() sobre el buffer de virtualAlloc(), modificando los bytes existentes por unos definidos por el binario (5050505050… y CF58585858…) los que tienen un propósito. El segundo recv() recibe una especie de cabecera de paquete que será utilizado para distintas validaciones como tamaño, cookie y el tipo. 1. size valida que la cabecera sea menor o igual a 11 bytes de tamaño 2. cookie valida que se envié la cadena Eko2022 3. type valida que se envié el carácter “T” 4. Integer Overflow es un valor que pertenece a la cabecera llamado size y debe ser menor a 0x0F00 que en decimal es 3840 Aquí podemos ver que existe una comparación con signo, el cual nos permite explotar la vulnerabilidad de Integer Overflow enviando un valor negativo que pronto será interpretado como positivo. Entonces si en el valor size de la cabecera enviamos 0xFFFF esto será transformado a 0x0000FFFF el cual es negativo y menor a 0x0F00 logrando la evasión de comparación. Cuando se logra la evasión entramos a llama otro recv() pero con un tamaño que controlamos, en este caso seria el word del valor negativo 0x0000FFFF y los bytes serán copiados a un buffer ubicado en el heap. Seguido se hace una llamada a la función renombrada como copy_data_heap_to_stack() con los argumentos.
Dentro de copy_data_heap_to_stack() tenemos una rutina que realiza una copia byte a byte desde el buffer heap al buffer stack, mediante un ciclo for() utilizando como size el 0xFFFF, provocando un desbordamiento de buffer de stack. Ahora lo importante es poder controlar registros o variables de stack que nos permitan seguir con la ejecución, para eso es necesario enviar bytes de tamaño controlado para poder modificar el valor del tipo y poder llegar a winExec(). Antes de llamar a winExec() se realiza un desplazamiento dentro del buffer y esos bytes son movidos al registro rax el que pisa la dirección de winExec(), por lo tanto no se podrá utilizar la función para ejecutar código. Por ultimo se realiza la llamada. Si recuerdan en la función memset() se modifican los bytes del buffer con 5050505050 y CF58585858. Ahora con el desplazamiento dentro del buffer mas 7 bytes, nos posicionamos justo en los 5050505050. Entonces cuando se realiza la llamada a winExec() llegamos a los 5050505050, los que se transforman en “pop rax” permitiendo hacer pop al stack y tomar el control del retorno que serian nuestras A’s con iret. Para esto veremos los pop rax y validamos con la información del stack. Con el siguiente código se comprueba los explicado anteriormente. |