Hoy veremos cómo resolver el nuevo reto de criptografía de la plataforma «Una Al Mes».
Introducción:
En esta ocasión, nos encontramos ante un reto de criptografía y tenemos que conseguir 3 flags.
Tan solo nos proporcionan un archivo «.py», cuyo contenido es:
Primera flag:
Bajo mi punto de vista, conseguir la primera flag es más complicado que conseguir el resto. Las siguientes flags son más directas.
Para esta parte tenemos que analizar la función introducir_licencia:
Se nos proporciona el valor de e, n y c y nos pide una key.
A priori, podemos pensar que para descifrar c y obtener la key podemos abusar del valor tan pequeño que tiene el exponente e y que esto no va a darnos dolores de cabeza, pero no es así 😅.
Si intentamos hacer la raíz cúbica de c, veremos que no obtenemos nada con sentido.
Es en este momento cuando me fijé en la pista que se nos proporciona en el código:
pista: la clave contiene un padding, y se encuentra en formato UAM{}
El padding se está aplicando directamente a m, es decir, al plaintext que se cifra. Es importante saber que solo podemos hacer la raíz cúbica de c si c < n, pero si le aplicas padding a m puede que c ≥ n. En este último caso, podemos conseguir el plaintext de la siguiente forma:
para un k perteneciente a Z
Por tanto, tenemos que ir incrementando el valor de c añadiendo múltiplos de n. Además, podemos saber que hemos conseguido el plaintext correcto, ya que, en ese caso, al cifrar el plaintext obtenido tendremos el mismo ciphertext que se nos da. Veámoslo mejor con el solver:
Tal y como se puede apreciar, el padding al que se referían consistía en una serie de espacios al inicio de la flag.
Segunda flag
Teniendo la primera flag podemos seguir con la ejecución del programa.
El programa nos pide la key que hemos obtenido y llama a la función decrypt_full_version pasando como argumento la key introducida. Si nos fijamos bien, en la función decrypt_full_version se llama a Fernet pasándole la key en base64:
Es importante saber que Fernet espera como key un valor de 32 caracteres, que es justamente la longitud de la cadena que hay entre {}. Por tanto, debemos proporcionar ese valor para continuar:
Seleccionamos la opción b y se nos muestra la información para obtener la siguiente flag:
Este reto es bastante trivial porque las distintas n comparten primos, por ello podemos ir obteniéndolos. Esto podemos hacerlo mediante el máximo común divisor.
Dado que la t solo se encuentra presente en n4, cuando obtengamos r podremos dividir n4 por r y conseguir t. El pseudocódigo es el siguiente:
El cifrado de m se lleva a cabo mediante el siguiente fragmento:
c = pow(pow(pow(pow(m,e,n1),e,n2),e,n3),e,n4)
Teniendo los primos es sencillo descrifrarlo, tan solo tenemos que ir descifrando desde fuera hacia dentro, es decir, comenzamos fijándonos en el primer pow:
pow(*pow(pow(pow(m,e,n1),e,n2),e,n3),*e,n4)
Se eleva pow(pow(pow(m,e,n1),e,n2),e,n3) a e (mod n4). Esta es la primera parte que tenemos que descifrar. Sabemos que n4 = r * t y teniendo los primos podemos calcular d y descifrarlo:
ct4 = rsa_decrypt(r,t,n4,c,e)
Tras descifrar esta parte, conseguiremos lo que he denominado ct4.
El siguiente fragmento a descifrar es:
pow(pow(pow(m,e,n1),e,n2),e,n3)
Los dos primeros pow corresponden a ct4, por tanto, se eleva ct4 a e (mod n3). Para descifrarlo seguimos el mismo proceso que antes:
ct3 = rsa_decrypt(p,r,n3,ct4,e)
Seguimos así hasta llegar al final y obtener el valor de m. El script final es:
Tercera flag
Teniendo la segunda flag, podemos introducirla en el código y continuar con la ejecución. Nada más introducirla, el programa escupe la tercera flag:
Con esto terminamos. Ha sido un reto muy entretenido. Muchas gracias a la gente de Hispasec por desarrollarlo.
Espero que os haya gustado y, lo más importante, que hayáis aprendido
DiegoAltF4
Inicio
Deja una respuesta