Otro Capture The Flag como todos en el mundillo conocemos o "Reto de Ciberseguridad"  de esta serie de CTF con el Nivel 3 al que hemos llamado "Nop Nop Nop".

Podéis bajaros el ejecutable pinchando en la imagen:

Capture-de-Flag-Nivel-3

Resolución CTF - Nivel 3 : Nop Nop Nop

Hola Hackers!!!!
Nivel 3. Tenemos 2 binarios.

$ md5sum Level3 Level3.exe
47d9ef2069d646522dbb9cd9b303414e Level3
02be333c8732920d1131a195e5753eb1 Level3.exe

Antes de nada vamos a ejecutarlo para ver qué hace el programa:

image001

Parece que espera algo por parámetro y siempre sale un “90909090” (NopNopNopNop).

Lo cargamos con radare2 (de Linux) (después lo haré con IDA para ver las diferencias):

image002

image003

Lo analizamos:

image004

Desensamblo el main:

image005

Y tenemos una llamada a lo que parece una función en la que se algo relacionado con xor:

image006

Justo después hace una comparación con algo. Después estará el mensaje con la cadena 90909090.

Si nos hemos fijado al principio de main:

image007

Tenemos 2 string: “90909090” (local_18h) y “Prueba” (local_20h).

image008

Primero de definen una serie de variables, como vemos (esas que se ven de Prueba o 90909090 y un par más, justo las 2 de arriba local_8h y local_10h).

Comienza el programa y comprueba si se le pasa un parámetro. Si es que sí se va a la t y si es que no a la f:

image009

Mostrando el correspondiente mensaje de “no input”. Si hemos introducido algo, vamos a la función “xorencrypt”. Obtiene un resultado y la compara con 0. Sino es igual a cero (jne) salta a 0x40080e y muestra un mensaje (local_18h) que era 90909090.

image010

Si es igual mostrará otro (local_28h) que salía del “xorencrypt”.

Veamos la función “xorencrypt”:

image011

Aparecen nuestras variables local_28h y local_30h en donde obtiene el tamaño de lo que se le pasa en uno de los parámetros y lo guarda.

Lo mismo ocurre con el otro parámetro y local_10h y local_30h.

Después incrementa en 1 una de ellas (local_10h) y reserva memoria (malloc) con su contenido.

image012

Inicializa otra (local_4h) a cero y comienza lo que sería un bucle.

Algo así como:

For (local_4h = 0; local_4h < local_10h; local_4h++).

image013

Y ahí está el Michael Knight (KIT) de la cuestión…

Tenemos local_4h, local_20h, local_20h y local_30h, todas vistas anteriormente.

Sería algo como:

String_cifrado[local_4h] = cadena_con_xor_original [local_4h] xor Clave_por_parametro [local_4h % longitud_ Clave_por_parametro]
La clave de todo esto está en ese “xor eax,esi” que se ve y ¿por qué no es tan evidente? Porque depende de lo que le pases por parámetro, no está “a fuego”.
Si le pasas una “A”, “A” será un 0x41 (65), “B” será 0x42 (66), etc… De ahí que no se vea directamente, por lo que hace falta hacer algo, conocido como… ¡¡¡FUERZA BRUTA!!!

Tranquilos, lo puse fácil, está entre la A y la Z.

O sentido común. En la Wikipedia podemos encontrar una explicación de lo que haría la función XOR

image014

Supongamos que queremos realizar un xor de la palabra “Hola” con la “A” (0x41) y nos saldría, antes:

image015

Resultado:

image016

Si realizáramos la operación inversa, tendríamos, después:

image017

Resultado:

image018

Mismo resultado por lo que podéis ver.

Por último solamente queda comparar lo que salga de la función con los 6 primeros caracteres y comprobar que empieza por “Prueba”. Si es así, mostrará el mensaje completo, utilizará el valor único (1 solo carácter – 0x[a-z0-9]{2} para cada valor del array).

Vamos al IDA, las variables:

image019

Aterrizamos en la función main:

image020

Igual que con radare2, se ve lo mismo.

image021

Función xorencrypt que vimos antes, no me quiero repetir….

image022

Vamos a verlo gráficamente:

image023

image024

image025

Con los cortes en las imágenes no se ven tan bien, sin ellos, sí se ve.

image026

La función xorencrypt:

image027

Y el xor del que hemos hablado:

image028

Es exactamente igual.
¿Y cómo resolvemos esto? No sé lo que tengo que pasarle.

Solución 1 (Shell version):
¿Qué charset utilizaré? A..Z, a..z, 0..9.

image029

Por lo que ya sabemos el valor del contenido de:

image030

Solución 2 (Didier Stevens version):
Didier Stevens se ha currado una herramienta muy útil con la idea de buscar en un fichero cadenas cifradas con XOR, justo lo que hace nuestro programa. Y además sabemos que lo compara con algo, “Prueba”, por lo que podemos utilizarla de la siguiente manera:

image031

image032

Solución 3 (Radare2 version):
Abrimos el CTF con Radare2, analizamos, buscamos la cadena que realizará el XOR, nos posicionamos en el offset adecuado, le damos un tamaño, realizamos el xor y vemos el resultado.

image033

image034

Solución 4 (r2pipe version):

¿Qué es r2pipe?

image035

La API para interactual con radare2.

`import r2pipe

offset = "0x004008b4"
xorkey = "52"

r2 = r2pipe.open("./Level3")
r2.cmd("e io.cache=true")
print ("Antes...")
r2.cmd("s " + offset)
print r2.cmd("ps 16 @ " + offset)
r2.cmd("b 16") # le da un tamanio al buffer
print ("Aplicando xor con 0x" + xorkey + "...")
r2.cmd("wox " + xorkey + " @ " + offset) # realiza un xor con 0x41 en donde esta la cadena cifrada
print ("Despues...")
print r2.cmd("ps 16 @ " + offset) # muestra la cadena descifrada
`

image036

Solución 5 (IDA version):
Abrimos IDA y vemos a la zona donde está la cadena cifrada:

image037

Pulsamos <SHIFT><F2>, nos abre una ventana donde podemos ejecutar scripts de IDA (IDC) y añadimos el siguiente código:

image038

image039

Ponemos una dirección de inicio, una de final y pulsamos “Run”.

BONUS - CASO REAL:

Mirai
mirai.x86: 7e17c34cddcaeb6755c457b99a8dfe32
Localizamos la zona en donde se realiza el descifrado de la configuración:

image040

En este caso, se descifra realizando un xor con 0x22.

image041

Esta son las cadenas cifradas y que hay que descifrar.
Aplicamos el xor con 0x22 a dicha zona y ya vemos el contenido de la configuración.

image042

Vemos la cadena MIRAI

Espero que os haya gustado.