Reto CTF Exploiting 2019

Primero que todo verificamos las protecciones que tiene el binario utilizando Process Hacker u otro a gusto del usuario, podemos observar que no existe nada DEP y ASLR Disable para el binario así que no tendremos problemas.

protecciones

Ahora como el binario necesita a exploiting.dll para su ejecución ponemos en análisis esta dll y encontramos una función Prt la cual nos puede servir para encontrá un salto al stack si fuese necesario. Ahora de todas maneras lo revisaremos mas adelante.

exploiting_dll

Empecemos con el juego, entonces ejecutamos el binario a ver que esta pasando o si el mismo necesita algún ej: (archivo, argumentos, data input, etc).

En la primera ejecución nos muestra el siguiente mensaje “Estas muy cerca de tu bof amigo… pero esto no puede ser si no he hecho nada, bueno sigamos viendo que pasa.

ejecución_1

Entonces cargamos el binario en un debugger. a partir de aquí vemos que el binario necesita unos argumentos para decidir porque flujo seguir.

Ahora como se puede ver claramente la flecha roja apunta al mensaje que obtuvimos sin hacer nada esto paso porque no utilizar argumentos. no nos sirve 😔.

argumentos_0

Probemos con un argumento y nos muestra el siguiente mensaje “Ups!! Try Harder amigo…”.

ejecución_2

Este flujo sigue el camino del primer cuadro morado img:argumento_0 al reconocer un argumento ingresado, donde entra a la funcion _main(char * argu). Aquí nos encontramos con lo siguiente que puede ser interesante, 2 comparaciones de un largo de cadena y una función strcpy() 🤔 prometedor.

argumento_1

Como ya se observa si el argumento no cumple cierta condición se va por la flecha roja e imprime el mensaje Ups!.

De lo contrario toma el largo de la cadena ingresada y lo compara con 0x5A y luego con 0x63, esto quiere decir que si el largo de la cadena esta entre estos valores podemos llegar a la función strcpy(), Acá se copiando una cadena de largo 90 y 99 bytes a un buffer (IsDebuggerPresents) de tamaño 100 bytes asi que no existe overflow 😔.

sudoC_argumento_1

Por ahora entendemos que al ingresar un argumento es importante para seguir el flujo pero si volvemos a ver img:argumento_0 nos damos cuenta que necesita 3 argumentos en total.

Si ingresamos 2 argumento nos muestra el mensaje de img:ejecución_1, pero con 3 argumentos cargamos exploiting.dll que utiliza el programa con LoadLibrary() y hace una llamada a Prt() con GetProcAddress(), donde cargara código que utilizaremos mas adelante.

load_exploiting.dll

Entonces solo nos queda analizar este flujo, si o si va por aquí 😏. Entonces después de cargar la *.dll en memoria esta pasa 2 argumentos argu_1 y argu_2 a una función _atoi(x,x) que claramente no es atoi así que veamos que hace.

argumentos_2_y_3

Ahora que condiciones deben cumplir estos 2 argumentos pasados a _atoi() para evitar los mensajes molestos de “El curso te espera amigo :)...” y “Vamos tu puedes no te alejes…”.

Primero verifica que el segundo argumento no sea 0, cumpliendo esto se enviá a strchr() para hacer una búsqueda de 0x2E (es igual a “.”) en la cadena. Si ese byte existe llegamos a la funcion _seek() donde se pasa el tercer argumento ingresado, sigamos...

funcion_atoi()

Ya dentro de _seek() nos encontramos lo siguiente, que el largo del tercer argumento debe ser mayor a 0x64 siendo así entramos a _printf() enviando nuevamente el tercer argumento. De lo contrario veremos un mensaje que dice “Frio Frio…”.

funcion_seek()

Ahora que estamos en _printf() y esperemos que sea el ultimo flujo 😅. Bueno vemos que el largo del tercer argumento es comparado 0x65, entonces debemos concluir que el tercer argumento debe tener un tamaño mayor 100 y menor a 102. Si este tamaño es mayor entra en un ciclo de 10 vueltas donde imprime un Sending — num*.

Ya cumpliendo todas las condiciones, lo siguiente es super simple, el binario ejecuta un scanf() y espera que el usuario ingrese datos por teclado estos son almacenados en un buffer de tamaño 6000 creado en el heap y luego son imprimido con el mensaje “LOL:AAAAAA…”.

Después este buffer es pasado a otra función strchr() para buscar dentro si contiene un byte 0x2D (es igual “-”). Existiendo esto nos saltamos el mensaje “El curso te espera amigo :)…” y entramos en recta final a un strncpy() el cual no debería ser vulnerable ya que se controla el tamaño a copiar pero bueno esto no siempre es correctamente aplicado.

Que sucede aqui copiamos en un la data obtenida por scanf() en un buffer de 1000 con un tamaño de 1100 strncpy(*buffer, data,1100) despues hacer la copia de los bytes sobreescribimos el retorno 😎.

funcion_printf()

Como conclusión necesitamos cumplir las siguiente condiciones para llegar el desbordameinto:

  • argu_1 -> ‘a’ (lo que sea)
  • argu_2 -> ‘.’ (condición)
  • argu_3 -> ‘b’ *101 (condición)
  • guion -> ‘-’ (para la data)

Si ejecutamos el script podemos ver que inyectara lo mismo que hice manuelmente.

manual

Bien si ya tenemos todo solo nos queda crear el exploit. Primero cargaremos unas librerias comunes y seteamos las variables que ya sabemos y lo enviamos como argumento al binario con popen4.

exploit_parte1

Despues del envio de argumentos enviamos la data que esta esperando scanf().

exploit_parte2

Despues de la ejecucion vemos que el retorno esta pisado con A’s, lo podemos observar en el stack y dump de memoria, ahora nos queda buscar algo para poder saltar al inicio del stack.

crash

El siguiente paso sera encontrar el offset exacto el cual pisa el retorno y para eso utilizaremos un pattern especialmente uno propio.

create_pattern

Ya podemos ver que el retorno fue pisado con 0x326A4231 donde lo calculamos con la tool y obtendremos el valor exacto de 1055 para llegar donde queremos que es EIP.

eip
offset_pattern

Solo no quedabuscar un salto tipico como jmp, call o un retn al registro de ESP, para ello veremos las protecciones de los modulos. Vemos que el binario y la dll no estan protegidas asi que usaremos la dll y no el binario para saltar ASLR ya que le binario contiene nullbyte y no estamos con un exploit unicode.

modulos

Pero como pudimos ver al inicio cuando analizamos exploiting.dll encontramos un jmp esp en la dirección 0x6D881457 en la función _Prt(). Usaremos esta direccion para pisar el retorno, modificando el flujo para que nos lleve de vuelta al stack donde pondremos nuestra shellcode quedando de la siguiente manera.

exploit_parte3
control_retorno

Ya tenemos el control y todo pero nos encontramos con un pequeño problema que es facilmente solucionable. Cual es este problema?

Tenemos poco estapacio de memoria donde caemos despues del retorno por eso necesitamos alinear un poco la parte alta del stack con el registro ESP.

para esto hay muchas formas de hacerlo pero en esta ocacion utilizaremos un sub esp, *?* para que decremente la direccion de ESP y asi suba al inicio del buffer y luego hacemos una llamada a ESP con un call ESP o un jmp ESP.

control_buffer

El exploit quedara de la siguiente manera, entonces cuando lo ejecutamos nos detenemos en el salto ESP para validar la resta.

exploit_parte4

Entes de la resta.

alineacion_esp1

Despues de la resta fijarse en el registro ESP donde queda apuntando ahora tenemos 0x1f7 que son 503 bytes para poner nuestra shellcode 😎.

alineacion_esp2

Ya nos queda la parte final y solo es validar los badchar con un simple array para saber cual es permitido o del gusto del binario.

badchar

Como resultado obtenemos estos byte malos ‘\x00\x20\x1a\x09\x0a\x0c\x0d\x0b’, ahora queda lo facil crear una shellcode con metasploit filtrando estos bytes o simplemente crear una shellcode de forma manual e ir jugando con las codificaciones xor como las tipicas shellcode polimórficos.

Ejecucion_final_exploit

Exploit:

https://github.com/s1kr10s/Reto-CTF-Exploiting-2019

www.exploiting.cl By Miguel Méndez Z.

By3…