SSCTF 2016 - Crypto 100 - HeHeDa WriteUp
En esta entrada, se presenta una solución al reto HeHeDa, perteneciente a la categoría crypto del SSCTF 2016 Quals. Deseamos que disfruten de su lectura, tanto como nosotros redactándola.
Descripción
La descripción que nos dan es la siguiente:
Primera aproximación
Tras descargarnos un fichero ‘Algorithm1-577265e1.py’. Lo primero que llama la atención es el valor de la variable:
Lo cual denota, que lo más inmediato es descubrir la key, que con toda seguridad será la usada para cifrar el contenido de:
Además, deja claro que la longitud de la contraseña es de 8 bytes:
También llama poderosamente la atención, los comentarios que hay al final del fichero:
Un galimatías que recuerda mucho al código binario. De hecho, si nos centramos en la siguiente función:
Se ve claramente que es justo eso, un valor codificado a binario en el que el 1
se sustituye por |
y el 0
por O
.
Troceando el código
Generación de arrays
El próximo paso, es ir viendo sentencia a sentencia que es lo que hace el código para cifrar un texto plano ‘plain’ con una clave ‘key’.
Al realizar esta tarea, en seguida nos damos cuenta de que el algoritmo genera dos arrays de bytes:
Arrays cuyo tamaño es determinado por la longitud del texto a cifrar y que son rellenados, a través de las listas A
y C
, cuyo contenido son 256 bytes (supongo que generados aleatoriamente).
Por tanto, lo importante aquí es que la generación de esos arrays no nos vale para demasiado, pues siempre se generará igual independientemente del texto a cifrar que se le pase (salvo la longitud).
Cifrado
Continuando con el análisis del algoritmo, observamos que de las dos tablas generadas anteriormente, es en t2
en donde se centrará el resto del algoritmo y es en última instancia quien contendrá la cifra.
A priori parece que por cada byte de t2
se realiza una asignación, una operación de desplazamiento y un xor, repetido todo ello 16 veces. Por lo que parece casi imposible poder revertir el algoritmo. Es más, apostaría incluso, que se trata de un ‘algoritmo de una sola vía’. Es decir, que únicamente nos valdría para cifrar, pero no para descifrar.
Sin embargo, en el trozo de código anterior hay un fallo muy grave y no es otro que el de aplicar el proceso de cifrado byte a byte y no por bloques de bytes. Esto, como ya veremos más adelante, nos permitirá someterlo a un ataque por fuerza bruta que nos ayude a descubrir la clave con la cual fue cifrado un texto.
Como prueba de esto, vamos a ejecutar el algoritmo repetidas veces, con las siguientes keys y nos fijaremos en el valor de t2
antes de su codificación:
'abaaaaaa' => CB 3F 7D 3B AF 82 C1 C5 5D 2A 9A 54 08 3C
'aabaaaaa' => CB 93 D0 3B AF 82 C1 C5 5D 07 81 54 08 3C
Fases
En este punto, ya podemos intuir que el éxito se obtendrá del desarrollo de dos fases:
- Hacer Brute Force para obtener la key
- Obtenido el paso 1, hacer Brute Force para obtener la flag.
Fase 1: Obtención de la key
Para poder obtener la key, es necesario tener una cifra y eso es justo lo que nos dan con:
Como ya comentamos anteriormente, esto no es más que una codificación binaria, de la cual podemos recuperar sus bytes:
26 7C 9B 5B A0 2A F9 DC D0 29 3C E1 F7 A5 59 69 6E D2 06 2A E9 5B 60 E5
Por tanto, lo que hay que hacer es, limitar el algoritmo a una función y devolver t2
en cada llamada:
A esta función, se le pasará una key que irá cambiando byte a byte hasta que tenga una coincidencia con los bytes de la cifra. Como sabemos que ésta es de 8 bytes, tan solo necesitamos los primeros 8 bytes de la cifra (26 7C 9B 5B A0 2A F9 DC
).
Para ello, añadimos al script la siguiente porción de código:
y cuya salida al ejecutarlos es:
Aunque casi hemos obtenido la key, podemos comprobar como en algunas parte de ella existen colisiones, esto es, que distintos valores obtienen el mismo resultado. En el siguiente diagrama apreciamos mejor la lectura anterior:
¡Es decir, tenemos 8 keys candidatas!:
@&#qD93_
@N#qD93_
@&#qDT3_
@N#qDT3_
^&#qD93_
^&#qDT3_
^N#qD93_
^N#qDT3_
¿Qué podemos hacer? La respuesta es que tan solo tendremos que probar todas en la fase 2 y ver los resultados obtenidos.
Fase 2: Obtención de la Flag
Esta fase, es exactamente igual a la primera, salvo que ahora hay que buscar coincidencias con la Flag en vez de con la key.
Por tanto, modificamos:
- la signatura de la función ‘algorithm’ de esta manera:
- comentamos la la sentencia de asignación de la variable ‘plain’:
- la flag codificada (27 bytes) que nos dan es esta:
36 B8 7E B8 D0 D4 F8 7B 26 D5 F0 2B 01 B8 64 E9 75 21 11 0D 3C F1 59 EC 74 99 85
- modificamos la porción de código que añadimos en la fase 1 de esta manera:
El resultado obtenido de la ejecución de este script es:
Como se aprecia, la única coincidencia que contempla 27 caracteres es:
Descarga en PDF
Si has llegado hata aquí y te ha gustado la entrada, tal vez quieras descargartelo en PDF. En tal caso, puedes hacerlo desde aqui:
HeHeDa.pdf |
EOF
Generalizando, este CTF es sin duda de los más completos y duros. Sin embargo, es ideal para curtirse en este mundillo que a tantos nos apasiona.
Nuestra más sincera enhorabuena a los ganadores y a todos aquellos te@ms españoles que hayan participado en él.
Hay una fuerza motriz más poderosa que el vapor, la electricidad y la energía atómica: la voluntad.
Albert Einstein