
🔪 PoC del ataque CRIME : un oráculo de compresión ataca CVE-2012-4929 🔪
El ataque CRIME: un ataque de oráculo de compresión CVE-2012-4929 descubierto por Juliano Rizzo y Thai Duong;
En un ataque de oráculo de compresión, el uso de compresión de datos adaptativa sobre una mezcla de texto plano elegido y texto plano desconocido puede provocar cambios sensibles al contenido en la longitud del texto comprimido que pueden detectarse aunque el contenido del propio texto comprimido esté cifrado. Esto puede utilizarse en ataques de protocolo para detectar cuándo el texto plano conocido inyectado es incluso parcialmente similar al contenido desconocido de una parte secreta del mensaje, reduciendo en gran medida la complejidad de una búsqueda de coincidencia para el texto secreto. Los ataques CRIME y BREACH son ejemplos de ataques de protocolo que utilizan este fenómeno.
El ataque CRIME permite recuperar datos cifrados enviados por un cliente a un servidor utilizando la longitud de los datos cifrados. No permite recuperar la clave privada utilizada para cifrar el mensaje o la solicitud HTTP.
Muchos artículos explican cómo funciona el ataque CRIME, pero esta es la mejor explicación que he encontrado en internet:
Este ataque no es realmente complejo; la parte realmente interesante es la implementación, que es un poco diferente de la "teoría".
Veamos el método ingenuo tal como se describe en el artículo; es una buena manera de entender cómo funciona:
El atacante puede controlar las solicitudes enviadas por el cliente (usando javascript, por ejemplo). El objetivo es recuperar la cookie secreta. El atacante envía múltiples solicitudes como esta y comprueba la longitud de los datos cifrados:
Dado que cookie=q coincide con cookie=quokkalight de la cookie secreta, la longitud de los datos cifrados será la misma y el atacante sabrá que ha encontrado un byte.
Pero este método falla a veces y no se puede confiar en él, así que en su lugar usaremos otro método.
Primero enviamos una solicitud con el carácter que queremos encontrar seguido de varios caracteres que no pueden encontrarse en la solicitud inicial, como algunos caracteres especiales: chr(i) + "#:/[@/&". Luego enviamos una segunda solicitud pero invertimos la carga útil así: "#:/[@/&" + chr(i) y comparamos las dos longitudes. Si len(enc(req1)) < len(enc(req2)) entonces hemos encontrado un byte. Este método se llama two_tries y es mucho más fiable:
¡El atacante ha encontrado un byte!
if len(enc(request1)) < len(enc(request2)):
print("found byte")
El método two_tries que implementé es totalmente recursivo, pero ¿por qué? A veces, se puede encontrar más de un byte porque la compresión coincide con múltiples patrones.
Tomemos el secreto: cookie=quokkalight. Si ejecutamos el algoritmo two_tries, encontraremos el siguiente resultado:
result 1: cookie=quokie=quokie=quokie=quokie=quokie=
result 2: cookie=quokkalight
El algoritmo necesita recorrer todos los caminos del árbol para encontrar todas las soluciones posibles. Podemos ver todos los resultados como un árbol que se puede representar así:

La prueba de concepto del ataque CRIME contra el modo de cifrado de flujo se puede encontrar en el archivo: CRIME-RC4-poc.py. Es una implementación en Python de la explicación anterior.
python3 CRIME-RC4-poc.py
Demostración completa y resultado:
Cuando se usa el modo de cifrado CBC con AES o DES, el ataque no es tan simple como con RC4. Como todo se divide en bloques, el ataque es un poco más complicado (no demasiado).
Por ejemplo, digamos que usamos AES con modo de cifrado CBC; el bloque se dividirá con una longitud de 16 y se añadirá un padding al final si len(data)%16 != 0.
En el modo CBC, es importante señalar que la carga útil payload=rand producirá una longitud de 16 y no de 12, ya que se añadirá un padding al final de los datos antes del cifrado. Por lo tanto, nuestro ataque anterior no puede funcionar.
Ejemplo:
En este ejemplo, la longitud siempre será la misma porque si añadimos o quitamos un byte, la longitud siempre será la misma; solo cambiará el padding. El atacante solo ve los datos cifrados y no tiene forma de conocer el padding a partir de los datos cifrados.
Solución: jugar con la especificación del modo CBC, de modo que la longitud del padding sea 1 añadiendo un valor aleatorio en la variable GARB (en el parámetro GET, ya que el atacante controla los datos GET y POST).
Si el byte coincide con un patrón, la longitud será la misma; si no coincide, la longitud será diferente.
A continuación, solo tenemos que usar el mismo método explicado en la parte de RC4; solo añadimos un paso antes.
adjust_padding() para tener un padding de longitud 1two_tries_recursive() y podemos encontrar el FLAG secreto.python3 CRIME-cbc-poc.py
muy pronto...
\ /
\ _ /
----/_\----
x--------------( . )--------------x
x|x | |_|\_/|_| | x|x
x x x x
https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/ssl_attacks_survey.pdf https://github.com/cloudflare/cf-nocompress https://www.ekoparty.org/archive/2012/CRIME_ekoparty2012.pdf https://security.stackexchange.com/questions/19911/crime-how-to-beat-the-beast-successor/19914#19914
| Solicitud | longitud |
|---|
| GET /cookie= DATA cookie=quokkalight | 80 |
| GET /cookie=a DATA cookie=quokkalight | 81 |
| GET /cookie=b DATA cookie=quokkalight | 81 |
| GET /cookie=. DATA cookie=quokkalight | 81 |
| GET /cookie=q DATA cookie=quokkalight | 80 |
| Solicitud para recuperar byte q | longitud |
|---|
| GET /cookie=a~#:/[@/& DATA cookie=quokkalight | 81 |
| GET /cookie=~#:/[@/&a DATA cookie=quokkalight | 81 |
| GET /cookie=b~#:/[@/& DATA cookie=quokkalight | 81 |
| GET /cookie=~#:/[@/&b DATA cookie=quokkalight | 81 |
| GET /cookie=q~#:/[@/& DATA cookie=quokkalight | 80 |
| GET /cookie=~#:/[@/&q DATA cookie=quokkalight | 81 |
| bloque1 | bloque2 | bloque3 | longitud |
|---|
| GET /cookie= DA | TA cookie=quokka | light + PAD(11) | 48 |
| GET /cookie=a DA | TA cookie=quokka | light + PAD(10) | 48 |
| GET /cookie=b DA | TA cookie=quokka | light + PAD(10) | 48 |
| GET /cookie=. DA | TA cookie=quokka | light + PAD(10) | 48 |
| GET /cookie=q DA | TA cookie=quokka | light + PAD(11) | 48 |
| bloque1 | bloque2 | bloque3 | bloque4 | longitud |
|---|
| GET /GARBc | ookie= DATA coo | kie=quokkalight + PAD(1) | 48 | |
| GET /GARBc | ookie=a DATA coo | kie=quokkalight | PAD(16) | 64 |
| GET /GARBc | ookie=b DATA coo | kie=quokkalight | PAD(16) | 64 |
| GET /GARBc | ookie=. DATA coo | kie=quokkalight | PAD(16) | 64 |
| GET /GARBc | ookie=q DATA coo | kie=quokkalight + PAD(1) | 48 |