Latest Tweets

CTF Una-Al-Mes La casa de papel 1ª parte. Write-up

Obtención de los códigos web

Abrimos la página web del CTF: http://34.253.233.243/lacasadepapel/episodio1/puerta.php. Observamos un sencillo formulario web con dos cajas de texto, “Código 1” y “Código 2”. Antes de hacer pruebas a lo loco, comprobamos el código fuente de la página:

El código fuente de la página del CTF nos revela un archivo interesante: “login.js”

El archivo JavaScript “login.js” parece ser importante. Lo abrimos y nos encontramos con una única función, llamada conexion, que nos dará los dos códigos tras un sencillo proceso de parseado:

function conexion(){
    var Password = 
        "unescape%28String.fromCharCode%252880%252C%2520108%252C%25" +
        "2097%252C%2520110%2529%29:KZQWYZLOMNUWC===";
    for (i = 0; i < Password.length; i++)
    {
        if (Password[i].indexOf(code1) == 0)
        {
            var TheSplit = Password[i].split(":");
            var code1 = TheSplit[0];
            var code2 = TheSplit[1];
        }
    }
}

El código anterior nos muestra como se generan los dos códigos a partir de la cadena “Password”. El terminador que los separa es “:”. Por lo tanto, para el código2 basta coger todos los caracteres después de “:”:

KZQWYZLOMNUWC===

Siendo todo mayúsculas, y con la terminación “===” parecería que estamos ante una codificación Base32. Decodificamos:

$ echo -n “KZQWYZLOMNUWC===”|base32 -d
Valencia

Para el primer código lo que haremos es coger todos los caracteres antes del “:”. Tenemos esto:

unescape%28String.fromCharCode%252880%252C%2520108%252C%252097%252C%2520110%2529%29

Basta con darse cuenta de que los caracteres que empiezan con % están usando la codificación hexadecimal en HTML. Sabiendo esto, basta con convertirlos a sus correspondientes valores ASCII y nos queda:

unescape(String.fromCharCode(80, 108, 97, 110))

Básicamente tenemos una llamada JavaScript simple, que nos devolverá “Plan”.

Rellenamos los dos campos del formulario web con “Plan” y “Valencia”, y obtenemos el password del ZIP:

El password del ZIP tras descubrir como generar Código1 y Código2

Reversing del ejecutable

Descargamos el archivo ZIP y usamos el password “PR0F3SOR&R10” para descomprimirlo. Obtenemos un ejecutable para consola en Windows de 64 bits:

$ file episodio1.exe
episodio1.exe: PE32+ executable (console) x86-64, for MS Windows

Lo ejecutamos con Wine64:

$ wine64 episodio1.exe
System_Date: 05/16/18
Wrong date R3m0!

————-HINT———————
‘La persistencia de la memoria…’
————————————–
Press any key to continue…

Bien, ahora tenemos 2 maneras diferentes de resolver el reto. Parece evidente que el programa comprueba la fecha del sistema, y si no es la que espera, nos muestra el mensaje de error y el “HINT”. La primera manera de resolverlo es, pues, encontrando la fecha correcta a partir del HINT. La segunda es, lógicamente, haciendo reversing. Elegimos la segunda por ser esto un CTF de seguridad informática.

Análisis con radare

Ejecutamos un primer análisis con radare y buscamos la función main:

r2 -A episodio1.exe
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
— Setup dbg.fpregs to true to visualize the fpu registers in the debugger view.
[0x00401500]> afl~main
0x004011b0 44 834 -> 813 sym.__tmainCRTStartup
0x00401530 5 595 -> 527 sym.main
0x0040e960 3 28 -> 24 sym.__main
0x00419d50 1 6 sym.__getmainargs
0x00452d40 1 29 sym.std::domain_error::domain_error_std::stringconst__
0x00452d60 1 36 sym.std::domain_error::_domain_error__
0x00452d90 1 15 method.std::domain_error.~domain_error()
0x0046d410 2 99 -> 139 sub.std::domain_error.domain_error_std::stringconst___410

Cuánta porquería, está claro que esto fue escrito en C++ (puag). Vamos directos al OFFSET de la función main, pasamos al modo visual, hacemos algo de zoom y observamos el simple flujo del programa:

[0x00401500]> s sym.main
[0x00401530]> VV

El flujo del programa. Como se puede apreciar, lo ideal sería “caer” en el nodo de la izquierda.

En la figura anterior, si el flujo del programa cae en el nodo de la izquierda, obtendremos el mensaje de “Congratulations!!, Stealing Money $$$”.  Es lo que nos interesa, sin duda. ¿Cómo llega aquí? Fácil; se hace una comparación de fecha. Si la fecha no es la esperada, saltamos al nodo de la derecha en la figura anterior. ¿Qué fecha és esa? Simplemente recorremos la figura anterior hacia atrás, y observamos que la fecha está hard-codeada dentro del ejecutable:

[0x004015f2]> s sym.main
[0x00401530]> pd 20

La fecha está hard-codeada dentro del binario: 01/23/89″.

La fecha se encuentra en el OFFSET apuntado por “str.01_23_89”, y es “01/23/89”. Esto está en formato americano, con el mes y el día intercambiados. Así que la fecha del sistema debería ser: “23/01/1989”.

A partir de aquí, podemos resolver el reto de al menos de 2 maneras diferentes:

  1. Cambiamos la fecha de nuestra VM para que sea 23/01/1989.
  2. Parcheamos la instrucción de salto tras la comparación de fechas para que el flujo del programa caiga en el nodo de la derecha, sin importar la fecha de nuestro sistema.

Método 1: Cambio de la fecha (pa gandules ;-))

Cambiamos la fecha y ejecutamos de nuevo el binario para obtener la FLAG:

Obtención de la flag, método 1: Cambiamos la fecha del sistema.

Método 2: Parcheamos la instrucción de salto (sólo un poco más de trabajo)

Revisamos dónde se hace la comparación de fechas y qué instrucción de salto se ejecuta. Bastará con parchear dicha instrucción de salto para caer siempre en el nodo de la izquierda:

La comparación de fechas y el salto; si la fecha no es válida, se ejecutará el salto hacia el OFFSET 0x401677, el nodo de la derecha.

Bastará parchear el JE por un JNE y pelillos a la mar. Así que obtenemos el OFFSET de dicha instrucción y lo cambiamos. Primero debemos salir de radare y ejecutarlo de nuevo con “-w” para poder escribir sobre el binario:

$ r2 -w -A episodio1.exe

Nos situamos en la instrucción JE 0x401677:

[0x00000000]> s `/c je 0x401677~[0]`
[0x004015ec]> pd 1
| ,=< ;– hit0_0:
| ,=< 0x004015ec 0f8485000000 je 0x401677

Parcheamos el JE por un JNE; comprobamos que el cambio se ha producido, y salimos de Radare:

[0x004015ec]> wa jne 0x401677
Written 6 bytes (jne 0x401677) = wx 0f8585000000
[0x004015ec]> pd 1
| ,=< ;– hit0_0:
| ,=< 0x004015ec 0f8585000000 jne 0x401677
[0x004015ec]> q

El binario ya está parcheado, así que simplemente lo ejecutamos en nuestro equipo sin cambiar su fecha:

Obtención de la FLAG mediante parcheo de binario.

La flag, por supuesto, es:

UAM{e30f35ad8d9cb6efc0778539a669fa85}

Además, si utilitzamos la web http://md5decrypt.net/en/, y intentamos crackear el MD5, obtenemos precisamente: 01/23/89:

La flag es, en realidad, el MD5 de la cadena “01/23/89”.

Toni Castillo

@disbauxes

Transform your Hak5 Packet Squirrel into an automatic TOR annonymizer

Preamble

I’ve been testing some Hak5 devices recently. I have to admit that they are all incredible, easy to use and well-designed. The Packet Squirrel is an incredible small MIPS device, based on OpenWRT, full of possibilities. Although its main goal is to perform advanced MitM attacks, it can be used for the common good as well. Being a MIPS device, some of the most used and well-known utilities and programs are included, but of course some others are not. TOR, for instance, it’s not installed out-of-the-box. That’s not a problem, of course, because you can always get its sources and cross-compile it. So I thought that using the Packet Squirrel for routing all the TCP traffic from a “TARGET” computer would be nice. Instead of using the device to perform MitM attacks, this would showcase its possibilities in quite another way.

Get to know the device

Before trying to cross-compile TOR, we need to know which libraries and hardware the device runs on. So we connect the device to our computer using the “ETH IN” device, we power it on and we connect to it using an SSH session. Then we perform the usual commands to get the standard C library used, its Kernel version, OpenSSL version, system architecture, and so on:

uname -a
Linux squirrel 3.18.45 #13 Mon Oct 30 21:24:27 UTC 2017 mips GNU/Linux

cat /proc/cpuinfo |grep model
cpu model : MIPS 24Kc V7.4

ls -l libc.so.0
lrwxrwxrwx 1 root root 21 Oct 30 21:24 libc.so.0 -> libuClibc-0.9.33.2.so

busybox |head -1
BusyBox v1.23.2 (2017-09-06 11:27:56 UTC) multi-call binary.

That’s fine; but we still need to know if the architecture is Big Endian or Little Endian, and of course if the processor is either MIPSR1, MIPSR2, or whatever. There are myriads of ways to do so, but we can just grab a binary from the squirrel and use readelf. The “busybox” binary will do:

readelf -h busybox |more
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 01 00 00 00 00 00 00 00
Class: ELF32
Data: 2’s complement, big endian
Version: 1 (current)
OS/ABI: UNIX – System V
ABI Version: 1
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0x4038a0
Start of program headers: 52 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x74001005, noreorder, cpic, o32, mips16, mips32r2
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0

Now we have everything we need to start the cross-compilation of TOR. The following table summarizes all of our findings:

 

Component Software Version
Standard C Library uClibc 0.9.33.2
SSL OpenSSL 1.0.0
Linux BusyBox 1.23.2
Kernel Kernel for MIPS 3.18.45
Architecture MIPS 32 Big Endian MIPS32R2

Setting up the cross-compilation framework

Although there are a bunch of ways to setup a cross-compilation framework, I have chosen Buildroot. After downloading this version, I have changed some basic things according to our previous table. Mind me, this version of Buildroot ships with newer versions of uClibc and OpenSSL, but we can fix that later on. You can find my configuration file for the buildroot framework here.

After performing the first compilation, I modified the uclibc and openssl packages to meet the Squirrel versions. According to the Buildroot documentation, there are some ways to customize your environment but I went the quick and dirty way instead. First, I did the following changes to build uClibc 0.9.33.2:

  • I downloaded uClibc 0.9.33.2 under $BUILDROOT/dl: wget https://www.uclibc.org/downloads/uClibc-0.9.33.2.tar.xz.
  • I added the sha256sum of uClibc-0.9.33.2.tar.xz to $BUILDROOT/package/uclibc/uclibc.hash.
  • I changed uClibc version and package name in $BUILDROOT/package/uclibc/uclibc.mk accordingly.

After that, I did the same with the libopenssl package:

  • I downloaded libopenssl 1.0.0.s under $BUILDROOT/dl: wget https://www.openssl.org/source/old/1.0.0/openssl-1.0.0s.tar.gz.
  • I added its sha256sum to $BUILDROOT/package/libopenssl/libopenssl.hash
  • I changed libopenssl version and package name in $BUILDROOT/package/libopenssl/libopenssl.mk
  • I commented out the LIBOPENSSL_PATCH variable in $BUILDROOT/package/libopenssl/libopenssl.mk.
  • I moved all the patches to another directory to prevent the build system from applying them (because it was a different version, the patch command would fail): mv *.patch foo.

After all these changes, I performed the “make -j8” once again. At some point, when the libopenssl package was about to be installed, I got an error concerning the “install_docs” and “doc” rules. So I removed the “doc” directory from the EDIRS variable in $BUILDROOT/output/build/libopenssl-1.0.0s/Makefile along with the “install_docs” rule in the install rule. After performing the compilation again, the following error showed up: ../libssl.so: file not recognized: File truncated. So I deleted this truncated file and executed “make -j8” again. This time the compilation ended without errors and the new libraries were sucessfully installed.

Finally, I removed the entire libevent from my previous built: rm -rf $BUILDROOT/output/build/libevent* and then I re-compiled it using the new OpenSSL libraries: make -j8. The buildroot environment was ready to use.

Cross-compiling TOR

Because our Packet Squirrel does not include the libevent library, I decided to build TOR statically linking libevent with the resulting binary. The PAcket Squirrel does not have support for some well-known modern protections, so I disabled any hardening during the compilation as well. The configure command I issued was this:

./configure –target=mips-buildroot-linux-uclibc –host=mips-buildroot-linux-uclibc –build=x86_64-pc-linux-gnu –prefix=/home/tonic as/buildroot/target/opt/tor –enable-static-libevent –with-libevent-dir=/home/buildroot/buildroot/build/libevent-2.1.8-stable/.libs/ –e nable-static-zlib –with-zlib-dir=/home/buildroot/buildroot/build/libzlib-1.2.11 –disable-gcc-hardening –disable-linker-hardening –disable-tool-name-check –disable-threads –disable-asciidoc

After that, I built and installed TOR: make -j8 install.

Finally, I copied all the files under $BUILDROOT/output/target/opt/tor to the Packet Squirrel, on its USB pendrive (previously formatted using EXT4): scp -r $BUILDROOT/output/target/opt/tor root@172.16.32.1:/mnt/

The payload

Because this device does not have too much free space, I had to setup some directories on the USB pendrive to accommodate some TOR files (logfiles and the like). With that done, I wrote the following payload:

#!/bin/bash
# TOR payload
# 2018 by T. Castillo Girona
# This is a simple payload that allows to route all the DNS queries and TCP
# traffic from a TARGET through TOR.
 
LOGFILE=/mnt/tor/logs/payload.log
TOR=/mnt/tor/bin/tor
TORCFG=/mnt/tor/etc/tor/torrc
TORLOG=/mnt/tor/logs/tor.log
 
IPTABLES=/usr/sbin/iptables
 
function grab_target_ip() {
 
	target_ip=`cat /tmp/dhcp.leases |awk '{print $3}'`
	if [ ! -z "$target_ip" ]; then
		# Set the led to BLUE:
		LED B
		echo $target_ip
	else
		# Set the LED to fail:
		LED FAIL2
		echo "`date` STAGE2: TARGET IP : Not a DHCP lease" >> $LOGFILE
		sync
		echo ""
		# Stop the payload:
		exit 1
	fi
 
}
 
function start_tor() {
 
	if [ -x $TOR -a -r $TORCFG ]; then
		# Delete any previous log:
		rm -rf $TORLOG 2>/dev/null
		sync
		# Start tor:
		echo "`date` STAGE3: EXECUTING TOR" >> $LOGFILE
		sync
		$TOR -f $TORCFG	2>&1&
		# It may take a while until tor is ready; that's when
		# its log file says: Bootstrapped 100%: Done
		echo "`date` STAGE3: WAITING TO HAVE A VALID CIRCUIT " >> $LOGFILE
		sync
		while [ true ]; do
			cat $TORLOG|grep "Bootstrapped 100%: Done" 2>/dev/null
			sync
			if [ $? -eq 0 ]; then
				# Perfect, we've got a circuit!:
				LED W
				echo "`date` STAGE3: WE HAVE A CIRCUIT " >> $LOGFILE
				break
			fi
		done	
	else
		# No tor binary or no torrc.
		# We leave it here.
		LED FAIL3
		echo "`date` NO TOR OR NO TORRC FILE." >> $LOGFILE
		sync
	fi
 
}
 
function set_ip_tables() {
 
	# Enable redirection for UDP DNS packets:
	$IPTABLES -t nat -I PREROUTING 1 -p udp -i eth0 --dport 53 -j REDIRECT --to-ports 5353
 
	# Enable TCP redirection through TOR:
	# (don't enable redirection for 172.16.32.0/24):
	$IPTABLES -t nat -I PREROUTING 2 -p tcp ! -d 172.16.32.0/24 -i eth0 -j REDIRECT --to-ports 9040
 
	echo "`date` STAGE4: SETTING IPTABLES " >> $LOGFILE
	sync
 
}
 
function rerunTor() {
 
	echo "`date` STAGE4: RE-EXECUTING TOR " >> $LOGFILE
	sync
 
	# Get pid of TOR process and kill it:
	ptor=`pidof tor`
	if [ $? -eq 0 ]; then
		# Kill it:
		kill -9 $ptor
	fi
 
	# Re-execute it:
	start_tor
 
} 
 
function run() {
 
	# Set networking to NAT
	# (we get an IP from the network; we assign an IP to the target)
	# The target gets routed through the Squirrel.
	echo "`date` STAGE1: SETTING NETMODE NAT " > $LOGFILE
	NETMODE NAT
	sleep 20
 
	# Now, make sure our target has a valid IP assigned
	# by the squirrel. Case it has not, stop the payload.
	LED STAGE2
	targetip=`grab_target_ip`
	echo "`date` STAGE2: TARGET IP IS $targetip " >> $LOGFILE
	sync
 
	# Now, prepare our instance of Tor, make sure it is
	# running before doing anything else:
	LED STAGE3
	echo "`date` STAGE3: STARTING TOR " >> $LOGFILE
	sync
	start_tor
 
	# Now set the iptables rules to redirect DNS and
	# TCP traffic trhough TOR transparently:
	LED STAGE4
	set_ip_tables
 
	# Let's set the LED to Success:
	LED R SUCCESS
 
	# Every time the user press the button, we kill
	# tor, and re-run it again so that the circuit
	# gets changed every time.
	while [ true ]; do
		NO_LED=1 BUTTON
		# Once the button has been pressed, proceed:
		rerunTor
		LED R SUCCESS
	done
 
}
 
# This payload will only run if we have USB storage
[[ ! -f /mnt/NO_MOUNT ]] && {
	LED ATTACK
	run &
} || {
	LED FAIL1
}

This payload simply setup the Squirrel as a NAT device; it will get an IP from the network on its “ETH OUT” interface and it will assign a dynamic IP Address to the TARGET computer on its ETH IN device. All the traffic from the TARGET computer will be routed through the Squirrel, and thanks to the iptables rules, the UDP packets for DNS and all the TCP packets will be redirected through TOR. Everytime the button is pressed, TOR is killed and re-executed, so a new circuit is constructed.

This payload is far from being perfect, but it delivers. Feel free to improve this version. If you do not want to go through all the burden of cross-compiling TOR, you can download the binaries here. Just unzip it directly on the USB pendrive on the Packet Squirrel, copy the “payload.sh” to the desired switch directory, and enjoy!


Una al Mes Mision 004: Write-Up

Introducción

El cuarto reto de Una al Mes está dividido en 2 partes. Durante la primera parte debemos ser capaces de acceder a un servicio web sin conocer ninguna credencial. Una vez resuelta esta primera parte, podremos descargar un ejecutable Windows para X86_64 que nos devolverá la FLAG.

Primera parte: “esto va de galletas

Accedemos a la URL del reto (http://34.253.233.243/inicio.php) y nos aparece el mensaje de error siguiente:

Mensaje de error durante el acceso a la URL del reto.

El mensaje de error podría indicar que el código del servidor comprueba el campo “User-Agent” enviado por el navegador del cliente. Sin embargo, esto es una falsa pista. Si miramos el código fuente de la página, observamos el siguiente código JavaScript:

 $(document).ready(function(){
    $('#b-login').click(function(){
      $.post('login.php', {"username": $('#fieldUser').val(), "password": $('#fieldPassword').val()}, function(val, status){
        if (val == "ok"){
          location.reload();
        }
        else{
          $("#error").show();
        }
      });

Ya hemos identificado, pues, la página de login (http://34.253.233.243/login.php). Tal y como se ve en el código anterior, la página recibe simplemente 2 parámetros, “username” y “password”. Aquí es donde podríamos pensar que se trata de un ejercicio de fuerza bruta, lanzando peticiones HTTP POST contra login.php hasta que logremos entrar como usuario “fry”. De nuevo, estamos equivocados. La función en JS obtenerCookie(), de la misma página, nos da una pista de que esto va de galletas:

 function obtenerCookie(clave) {
      var name = clave + "=";
      var ca = document.cookie.split(';');
      for(var i=0; i&lt;ca.length; i++) {
          var c = ca[i];
          while (c.charAt(0)==' ') c = c.substring(1);
          if (c.indexOf(name) == 0) return c.substring(name.length,c.length);
      }
      return "";
    }

Ejecutamos Burp, hacemos una petición a inicio.php, y después enviamos dicha petición al módulo Repeater. Modificamos la URI por “login.php” y el método por “POST”. Finalmente añadimos el payload (username=test&password=test). Aunque no sabemos si la clave será idéntica al usuario, por probar que no sea:

Hacemos un POST contra login.php y el servidor nos deveuleve una cookie de sesión.

El servidor nos devuelve una cookie de sesión:

token=qTImqPNtVPNtVN%3D%3D;

Esto cada vez parece más un clásico CTF donde, para poder seguir, debemos ser capaces de “cocinar” la cookie de sesión y suplantar al usuario “fry”. Usamos un gestor de cookies en nuestro Firefox y añadimos esta cookie de sesión. Después recargamos la página “inicio.php”. Esta vez, se nos saluda:

Acceso como usuario “test” en “inicio.php” con la cookie de sesión.

Por supuesto, para poder avanzar debemos entender como está generada la cookie. La función en JS “obtenerCookie()” mostrada unas líneas más arriba es la clave. Fijémonos que dicha función itera entre todas las posibles cookies y, por cada una elimina los espacios en blanco que puedan encontrarse al principio de la cookie (ejecuta un ltrim()). Finalmente, busca el valor pasado como parámetro (test en este caso) al principio de dicha cookie, y si lo encuentra retorna el valor después de dicha cadena. Por el valor codificado en base64 de la cookie, sabemos que la longitud en texto claro ASCII de la cookie debe ser de 10 bytes exactos.

Probamos de codificar en base64 la cadena ”      test”:

echo ” test”|tr -d ‘\n’|base64
ICAgICAgdGVzdA==

Fijémonos que ICAgI podría ser substituido por qTImq, pero luego no tenemos dos patrones que se repitan en la cookie: CAgd != GVzd. Por el formato de la cookie obtenida, parecería que hay algún algoritmo de substitución que cifra el código base64 de la cookie.

Probamos ahora de codificar la cadena “test      “ en base64:

echo “test      “|tr -d ‘\n’|base64
dGVzdCAgICAgIA==

Aquí tenemos una posible pista sobre el cifrado utilizado por la cookie. Fijémonos que dGVzd se traduce en qTImq en la cookie original; así vemos que d=>q; G=>T; V=>I; z=>m; d=>q …, y entre caracter y caracter tenemos una rotación de 13 caracteres. Además, tenemos los dos patrones claros CAgiCAgI. Así pues, probamos de cifrar nuestra cadena base64 usando ROT13:

Hemos descubierto la receta secreta.

Ahora que ya sabemos como “cocinar” nuestra cookie, cambiamos “test” por “fry”, añadiendo un espacio en blanco más (fry + 7 espacios en blanco). Codifcamos en base64 y ciframos usando ROT13:

echo “fry       “|tr -d ‘\n’|base64
ZnJ5ICAgICAgIA==

El resultado es la cookie que mostramos a continuación:

Nuestra cookie acabada de salir del horno.

Sólo nos queda modificar la cookie en nuestro navegador por esta otra y recargar la página “inicio.php”. Esta vez obtenemos una URL con el archivo a descargar, segunda parte del reto:

Primera parte superada.

Segunda parte: “r2 es como el algodón, no engaña”

Descomprimimos el ZIP descargado; tenemos un ejecutable (test.exe) y un archivo que, probablemente, sea la FLAG cifrada: secretcode. Vemos que el ejecutable es un Windows de 64 bits para “consola”:

file test.exe
test.exe: PE32+ executable (console) x86-64, for MS Windows

Antes de ejecutar el binario, abrimos radare2 para analizarlo:

r2 -A test.exe

Nos situamos en la función main y observamos su código desensamblado:

Dentro de la función main de test.exe.

Aparte de comprobar si hay un depurador presente (jojojo, yo ni he picado porque he ido directo a leer el código desensamblado y no lo he llegado ni a depurar ;-)), vemos que hay una llamada a la función “check” antes de ejecutar el retorno y salir. Vamos a esa función y nos fijamos en su flujo de ejecución gracias al modo visual de r2:

El control path del programa que nos descifrará “secretcode”.

Parece evidente que el control path del programa debería acabar en la llamada a decrypt() para poder descifrar el archivo “secretcode“. Para llegar a dicha función, debemos pasar por la reproducción del sonido en la función “cool_melody()”. La flag la podemos ahora obtener de tres maneras diferentes:

  1. Ejecutamos el binario en modo emulación (ESIL) para que se ejecute la función decrypt sin tener ni que pasar por la ejecución del resto del programa.
  2. Analizamos la función decrypt() con r2 y, a partir de lo que parece la clave “tvB3Cj4iNxw4rjMNxhmX3DaXAuMG2e”, desciframos la FLAG.
  3. Seremos buenos, y analizaremos con r2 como llegar a la llamada de la función “cool_melody” y, desde allí, a “decrypt”.

 Para llegar a “cool_melody” basta con introducir en el parámetro pedido (número de pista) el valor 101 en decimal (0x65):

Si introducimos 101 como track, seguimos la ejecución y caemos en “cool_melody()”

La ejecución del programa seguirá hasta reproducir el “cool_melody” y nos hará una pregunta que es fácil de contestar porque la respuesta está hardcodeada en ASCII en el propio ejecutable “futurama“:

La respuesta a la pregunta está hardcodeada en el propio binario.

Así pues, sabemos que debemos escribir 101 como primer parámetro, y “futurama” como segundo en el programa. Esto hará que el control path del programa acabe en el OFFSET 0x401b99, abra el archivo “secretode”, y lo descifre con una llamada a decrypt(). El resultado podemos verlo a continuación:

Finalmente, la flag aparece descrifrada ante nuestros ojos.

Finalmente, la FLAG es:

UAM{m4y_th3_f0rc3_b3_w1th_y0u}

Toni Castillo @disbauxes