No cON Name CTF Pre Quals: Access Level 3
- October 2, 2013
- tuxotron

En este tercer y último reto nos enfrentamos a un fichero ELF. Este nivel fue el más fácil de los tres. Como veremos es súper sencillo.
Una vez bajamos el binario, lo primero es ejecutar file:
tuxotron@tuxotron-T530 ~/ctf/noconname2013quals $ file level.elf
level.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xb589d432799bf15343387fea63d4bdc00faa177c, not stripped
Está compilado con símbolos y demás. Esto nos facilitará mucho la vida. Lo siguiente fue pasarle el comando strings, pero éste no arrojaba nada interesante.
Cuando ejecutamos el fichero se nos pide que introduzcamos por teclado una clave:
tuxotron@tuxotron-T530 ~/ctf/noconname2013quals $ ./level.elf
| > Type to win, only what I want to read… | >
Nada más pulsemos una tecla, si no es la que la aplicación espera, la aplicación termina:
tuxotron@tuxotron-T530 ~/ctf/noconname2013quals $ ./level.elf
| > Type to win, only what I want to read… | > | | -> I DON’T THINK SO
Echemos un vistazo al fichero desde gdb.
Una vez cargamos el ejecutable, desensamblamos el main:
(gdb) disassemble main
Aquí buscamos la función que nos pide entrada por teclado y rápidamente vemos que justo después de cada carácter, éste se compara con lo que hay almacenado en la dirección 0x6033a0:
0x00000000004010f3 <+212>: call 0x400fef < getch > // Entrada teclado
0x00000000004010f8 <+217>: movsx eax,al
0x00000000004010fb <+220>: mov DWORD PTR [rbp-0x4],eax
0x00000000004010fe <+223>: mov eax,DWORD PTR [rbp-0x8]
0x0000000000401101 <+226>: cdqe
0x0000000000401103 <+228>: mov eax,DWORD PTR [rax*4+0x6033a0] // Comparación
0x000000000040110a <+235>: cmp eax,DWORD PTR [rbp-0x4]
Si miramos lo que hay en esa dirección:
(gdb) x/30s 0x6033a0
0x6033a0 <facebookctf_rocks>: " "
0x6033a2 <facebookctf_rocks+2>: ""
0x6033a3 <facebookctf_rocks+3>: ""
0x6033a4 <facebookctf_rocks+4>: "S"
0x6033a6 <facebookctf_rocks+6>: ""
0x6033a7 <facebookctf_rocks+7>: ""
0x6033a8 <facebookctf_rocks+8>: "U"
0x6033aa <facebookctf_rocks+10>: ""
0x6033ab <facebookctf_rocks+11>: ""
0x6033ac <facebookctf_rocks+12>: "R"
0x6033ae <facebookctf_rocks+14>: ""
0x6033af <facebookctf_rocks+15>: ""
0x6033b0 <facebookctf_rocks+16>: "P"
0x6033b2 <facebookctf_rocks+18>: ""
0x6033b3 <facebookctf_rocks+19>: ""
0x6033b4 <facebookctf_rocks+20>: "R"
0x6033b6 <facebookctf_rocks+22>: ""
0x6033b7 <facebookctf_rocks+23>: ""
0x6033b8 <facebookctf_rocks+24>: "I"
0x6033ba <facebookctf_rocks+26>: ""
0x6033bb <facebookctf_rocks+27>: ""
0x6033bc <facebookctf_rocks+28>: "S"
0x6033be <facebookctf_rocks+30>: ""
0x6033bf <facebookctf_rocks+31>: ""
0x6033c0 <facebookctf_rocks+32>: "E"
0x6033c2 <facebookctf_rocks+34>: ""
0x6033c3 <facebookctf_rocks+35>: ""
0x6033c4 <facebookctf_rocks+36>: "!"
0x6033c6 <facebookctf_rocks+38>: ""
Vemos que el primer carácter es un espacio en blanco y luego SURPRISE! Si metemos eso como entrada al programa:
level.elf > enter: SURPRISE! | > Type to win, only what I want to read… | > ********** | | -> Congratulations! The key is: | 9e0d399e83e7c50c615361506a294eca22dc49bfddd90eb7a831e90e9e1bf2fb
No cON Name CTF Pre Quals: Access Level 2
- October 2, 2013
- tuxotron

En el segundo nivel nos enfrentamos a una aplicación Android. Lo primero que hacemos aquí es expandir el .apk con la herramienta apktool.
Primero miramos el contenido del fichero AndroidManifest.xml, donde podemos ver la clase inicial de la aplicacion:
También nos encontramos en el directorio res con un subdirectorio llamado raw, el cual contiene 17 imágenes, 16 de las mismas parecen ser trozos de un QR-Code. Parece que nuestro objetivo es leer dicho código. El problema es que no sabemos el orden de los trozos.

Lo siguiente que haremos será echar un vistazo por el código de com.facebook_ctf.challenge.MainActivity. Para ello usamos otra herramienta llamada dex2jar y luego usamos la herramienta jad para decompilar dicha clase.
Dentro de la misma vemos un método llamado public void yaaaay() con el siguiente código:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 0x7f040005);
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), 0x7f04000d);
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), 0x7f04000c);
Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), 0x7f040004);
arraylist.add(bitmap);
arraylist.add(bitmap1);
arraylist.add(bitmap2);
arraylist.add(bitmap3);
Bitmap bitmap4 = BitmapFactory.decodeResource(getResources(), 0x7f040006);
Bitmap bitmap5 = BitmapFactory.decodeResource(getResources(), 0x7f04000b);
Bitmap bitmap6 = BitmapFactory.decodeResource(getResources(), 0x7f040002);
Bitmap bitmap7 = BitmapFactory.decodeResource(getResources(), 0x7f04000f);
arraylist.add(bitmap4);
arraylist.add(bitmap5);
arraylist.add(bitmap6);
arraylist.add(bitmap7);
Bitmap bitmap8 = BitmapFactory.decodeResource(getResources(), 0x7f040010);
Bitmap bitmap9 = BitmapFactory.decodeResource(getResources(), 0x7f040000);
Bitmap bitmap10 = BitmapFactory.decodeResource(getResources(), 0x7f040001);
Bitmap bitmap11 = BitmapFactory.decodeResource(getResources(), 0x7f04000e);
arraylist.add(bitmap8);
arraylist.add(bitmap9);
arraylist.add(bitmap10);
arraylist.add(bitmap11);
Bitmap bitmap12 = BitmapFactory.decodeResource(getResources(), 0x7f040007);
Bitmap bitmap13 = BitmapFactory.decodeResource(getResources(), 0x7f040003);
Bitmap bitmap14 = BitmapFactory.decodeResource(getResources(), 0x7f04000a);
Bitmap bitmap15 = BitmapFactory.decodeResource(getResources(), 0x7f040008);
Tiene toda la pinta que este código es el que pone todas las imágenes juntas para crear nuestro QR. Lo siguiente es averiguar que imagen corresponde con cada identificador. Para ello, usando la utilidad jad de nuevo, decompilamos el fichero R.class y en este vemos claramente la correspondencia entre los identificaros y los nombres de las imágenes:
public static final class raw
{
public static final int a = 0x7f040000; public static final int b = 0x7f040001; public static final int c = 0x7f040002; public static final int d = 0x7f040003; public static final int e = 0x7f040004; public static final int f = 0x7f040005; public static final int g = 0x7f040006; public static final int h = 0x7f040007; public static final int i = 0x7f040008; public static final int ic_secret = 0x7f040009; public static final int j = 0x7f04000a; public static final int k = 0x7f04000b; public static final int l = 0x7f04000c; public static final int m = 0x7f04000d; public static final int n = 0x7f04000e; public static final int o = 0x7f04000f; public static final int p = 0x7f040010;
public raw() { } }
Poniendo todas las imágenes en ese orden, tenemos 4 filas por 4 columnas, todas las filas parecen estar correcta, menos la segunda. La cuarta imagen de la segunda fila parece que está en su posición, como podemos vez por la franja negra, pero las 3 primeras están en sentido contrario.
Al final el código QR obtenido es el siguiente:

Y usando mi móvil como lector, obtuve: 788f5ff85d370646d4caa9af0a103b338dbe4c4bb9ccbd816b585c69de96d9da
No cON Name CTF Pre Quals: Access Level 1
- October 1, 2013
- tuxotron

En el primer nivel o el primer reto de la Pre Qual del CTF de la NoConName , nos encontramos con una página en la que se nos pide un clave (Key). Cuando introducimos algún texto, inmediatamente nos muestra un mensaje: Invalid Password! (a menos que hayas introducido una clave válida en el primer intento, lo cual me sorprendería :)).
Lo primero que podemos apreciar es que el mensaje viene de la típica ventana que muestra el navegador cuando se ejecuta un alert en javascript. Esto nos dice que la comprobación de la contraseña se hace (al menos parte de la misma) en el lado del cliente, es decir en nuestro navegador.
Lo siguiente sería ver el código javascript que se ejecuta cuando hacemos click en el botón Send. Mirando el contenido de la página vemos que la misma es muy sencilla y que incluye un fichero javascript llamado crypto.js, cuyo contenido es el siguiente:
Como vemos el fichero está ofuscado. Una de las técnicas típicas de de-ofuscar un fichero de este tipo es sustituyendo la función eval por alguna función que imprima el contenido, por ejemplo un alert o document.write. Yo usé el document.write, pero éste no muestra el código completo del fichero ofuscado y no hice por probar el alert porque pensé que haría lo mismo, pero acabo de probar el alert y funciona a la perfección. Como iba diciendo, el document.write no me funcionó, así que opté por pasar el contenido del fichero por un de-ofuscador online, concretamente usé http://crazydavinci.net/tools/javascript-decryptor-v2/. El resultado del mismo:
Mucho mejor ahora. La función que nos interesa de, aunque todas tienen su papel en el proceso, es la llamada encrypt, que es la que se llama cuando hacemos click sobre el botón Send.
Lo primero que hace encrypt es llamar a la función numerical_value pasándole como parámetro nuestra entrada y devuelve un número calculado en base al valor decimal ASCII de cada carácter de nuestra entrada multiplicado por su posición +1 en la misma, es decir, los primeros caracteres tienen menos peso que los últimos. Este detalle lo necesitaremos más tarde.
Volviendo a la función encrypt, ésta hace varias operaciones con el número devuelto por numerical_value y si el resultado es 0, entonces quiere decir que hemos encontrado una clave válida:
res=numerical_value(form.password.value);
res=res*(3+1+3+3+7);
res=res>>>6;
res=res/4;
res=res^4153;
if(res!=0)
{
alert('Invalid password!')
}
else
{
alert('Correct password :)')
}
La idea aquí es hacer las operaciones contrarias al revés. Partiremos del número 4153, ya que para que la operación: res=res^4153; sea 0, que es lo que deseamos, res debe ser igual a 4153. Recuerda que la operación XOR con dos números iguales es 0. La siguiente operación en reverso sería multiplicar 4153 * 4, luego desplazar dicho resultado 6 bits a la izquierda, o lo que es lo mismo multiplicarlo por 2^6 o lo que es lo mismo, multiplicarlo por 64 y la última operación sería, dividir el resultado la operación anterior por (3+1+3+3+7) ó 17, cuyo resultado final (redondeado) es: 62540. Este es el número que queremos obtener de la función numerical_value. Para ello, de forma manual, me puse a introducir ‘a’ hasta que llegué a superar dicho número, y luego jugando con los caracteres iniciales y finales, conseguí una cadena de caracteres que pasada a numerical_value me devolvía nuestro número: 62540. Dicha cadena es: ;9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+ Introduciéndola en la página del reto, conseguimos nuestra flag:
Congrats! you passed the level! Here is the key: 23f8d1cea8d60c5816700892284809a94bd00fe7347645b96a99559749c7b7b8
Buscar
Entradas Recientes
- Posts
- Reemplazando la bateria del AirTag
- OpenExpo Europe décima edición, 18 de mayo: El Epicentro de la Innovación y la Transformación Digital
- Docker Init
- Kubernetes para profesionales
- Agenda: OpenExpo Europe 2022 llega el 30 de junio en formato presencial
- Libro 'Manual de la Resilencia', de Alejandro Corletti, toda una referencia para la gestión de la seguridad en nuestros sistemas
- Mujeres hackers en ElevenPaths Radio
- Creando certificados X.509 caducados
- Generador de imágenes Docker para infosec