lunes, 9 de septiembre de 2013

Solución a la prueba 2 - Modificación de datos con AES CBC





La semana pasada colgamos en la web una prueba sobre cifrado, como la segunda parte de una serie de pruebas que estamos haciendo para que la gente conozca y pruebe de primera mano lo que se va a impartir en el curso de seguridad que comenzaremos este mes.

Esta prueba además, fue una prueba que inicialmente íbamos a poner en el CTF de la Kernel 2013 en Mugardos, pero que al final decidimos dejarla fuera de concurso y ponerla como previsualización del mismo.

El caso es que después de una semana nadie ha conseguido resolverla :) así que creo que se merece una explicación bastante detallada.

Antes de ir al grano, un poco de background.

AES


AES es una especificación de cifrado de bloques basado en Rijndael
Sin entrar en demasiados detalles técnicos, hay dos características fundamentales sobre AES que nos pueden dar una idea acerca de lo que es:

1 - Usa una función de expansión de clave pseudoaleatoria segura: Es decir, a partir de una clave relativamente pequeña (128, 192 o 256 bits en este caso), la función de AES consigue crear una clave expandida capaz de ser usada para cifrar todo el texto.
2 - El método de cifrado es de bloques, es decir, si tengo que cifrar un texto de 1000 bits, ese texto se dividirá en bloques y cada uno de ellos se cifrará por separado. En el caso de AES el tamaño de bloque es fijo: 128 bits (16 bytes)

Sobre su seguridad, podemos decir que hasta la fecha AES es uno de métodos de cifrado más seguros siempre y cuando la clave sea lo suficientemente compleja y su implementación sea correcta.

Este no es el caso de una implementación correcta, así que seguimos con más detalles sobre la prueba :D


CBC


AES se puede utilizar de diferentes maneras llamadas "modos", esto es, diferentes implementaciones para aprovechar la funcionalidad de AES, algunas son más adecuadas que otras para determinadas situaciones y cada una tiene ciertos requisitos a la hora de su implementación.

En esta prueba se usa el modo CBC (se ve en el cliente, más sobre esto más adelante) así que vamos a hacer una breve descripción del mismo.

Antes comentábamos que AES cifra por bloques de 128 bits, en el caso del modo CBC el cifrado de estos bloques se produce de la siguiente manera (esquema sacado de wikipedia):

CBC encryption.svg

Es decir, se divide el texto en bloques de128 bits y despues:

- Se hace XOR del primer bloque con un vector de inicialización IV
- El resultado se cifra con AES y  la clave
- Se hace XOR del resultado del paso anterior con el siguiente bloque
- El resultado se cifra con AES y la clave

Etc..

Y así conseguimos:
- Que el IV (que debería ser distinto para cada operación de cifrado) evite que dos cifrados del mismo texto sean iguales, por lo que evitamos los ataques de repetición
- Que cada bloque sea siempre de 128 bits, lo que AES necesita (el IV por lo tanto tiene que ser de 128 bits también)

A la hora de descifrar por lo tanto se hace la operación inversa

CBC decryption.svg

Por pasos : 
- Se descifra el primer bloque con AES y la clave y después se hace XOR con el IV
- Se descifra el segundo bloque con AES y la clave y se hace XOR con el primer bloque sin descifrar
- Se descifra el tercer bloque con AES y la clave y se hace XOR con el segundo bloque sin descifrar
etc

Esto nos lleva a dos conclusiones:

- Que el IV hace falta tanto como la clave para descifrar el mensaje (al menos el primer bloque), pero como con eso solo no se descifra el mensaje, se suele enviar junto con el mensaje, en concreto los primeros 16 bytes de un mensaje AES CBC suele ser el IV, como veremos en nuestro ejemplo más adelante.

- Lo importante: Que el XOR del IV a la hora de descifrar se aplica DESPUÉS de haber descifrado el texto con la clave 


Y con esta información ya estamos listos para resolver el problema



Reuniendo toda la información.



El enunciado de la prueba, que aún podemos encontrar en esta web nos presentaba un escenario poco prometedor, y mucha gente en cuanto vio AES y clave en blanco ya dejó de hacer la prueba, pero vamos a ver los detalles interesantes:

El cliente.py nos muestra bastante información acerca de la última petición que se hizo al servidor:
- Por una parte sabemos el IV que se utilizó: 8262850ee31a28351e9cc6da99438f6f
- Por otra parte sabemos el último texto que se cifró: -clave de laura-

La captura.pcap por otra parte nos da más información, puesto que en los paquetes está cifrado ese mensaje que salió del cliente

Abriendo esa captura con el wireshark, por ejemplo, vemos que además es la única comunicación en todo el fichero, así que podemos por ejemplo seguir la conversación (Click derecho, follow TCP stream) para ver el contenido, que es este

"8262850ee31a28351e9cc6da99438f6f2d78e1d2eb48ebf6f4442d61b5f0aca269342a926713ce09116203fd31f48f10Hola usuario normal, tu clave es: clavemuyfacil"

Entonces, sabemos que lo que el cliente envía cifrado al servidor es: 

8262850ee31a28351e9cc6da99438f6f2d78e1d2eb48ebf6f4442d61b5f0aca269342a926713ce09116203fd31f48f10

Donde los primeros 16 bytes es el IV 8262850ee31a28351e9cc6da99438f6f (esto ya lo sabíamos por otra parte, porque el cliente lo tenía como valor en la variable IV)


Entonces sabemos que 

8262850ee31a28351e9cc6da99438f6f2d78e1d2eb48ebf6f4442d61b5f0aca269342a926713ce09116203fd31f48f10 

es el cifrado de 

-clave de laura-

Como comentamos antes en la explicación de CBC el XOR del IV con el primer bloque se aplica después del descifrado con la key, así que sabemos que el servidor que reciba el mensaje lo primero que va a hacer con el es descifrarlo con AES y luego hacer un XOR de los primeros 16 bytes con los siguientes 16, es decir, va a hacer XOR de estas dos cosas:


82 62 85 0e e3 1a 28 35 1e 9c c6 da 99 43 8f 6f 
-  c  l  a  v  e     d  e     l  a  u  r  a  - 

¿Se empieza a ver la luz? :D
                              
Nosotros no podemos modificar el mensaje porque no sabemos la key para volver a cifrarlo, pero si podemos modificar el IV, porque se envía junto con el mensaje, y aprovecharnos del funcionamiento de AES para forjar un IV especialmente diseñado para cambiar el sentido del mensaje cifrado


Así que vamos a hacer esto en dos pasos, primero cambiamos el IV para que anule laura

82 62 85 0e e3 1a 28 35 1e 9c c6 da 99 43 8f 6f
-  c  l  a  v  e     d  e     l  a  u  r  a  -

xor                           l  a  u  r  a
                           6c 61 75 72 61

--------------------------------------------------------
                           aa bb ec 31 ee

Y ahora cambiamos otra vez el IV para añadir admin en su lugar

82 62 85 0e e3 1a 28 35 1e 9c aa bb ec 31 ee 6f
-  c  l  a  v  e     d  e                    -

xor                            a  d  m  i  n
                            61 64 6d 69 6e

--------------------------------------------------------
                            cb df 81 58 80


Así que tenemos que con el mismo mensaje cifrado pero con un IV distinto


8262850ee31a28351e9ccbdf8158806f2d78e1d2eb48ebf6f4442d61b5f0aca269342a926713ce09116203fd31f48f10 
descifrará como : 
-clave de admin- 

Probamos ese string en el servidor y..


# nc 188.165.132.186 9995
8262850ee31a28351e9ccbdf8158806f2d78e1d2eb48ebf6f4442d61b5f0aca269342a926713ce09116203fd31f48f10
Hola admin, tu clave es: thekeyisalie


thekeyisalie!


Gracias por aguantar hasta aquí y hasta la próxima prueba :D


No hay comentarios:

Publicar un comentario