No cON Name CTF Pre Quals: Access Level 1

level1.png

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