
🔪 Attacco CRIME PoC : un oracolo di compressione attacca CVE-2012-4929 🔪
Attacco CRIME: un attacco oracle di compressione CVE-2012-4929 scoperto da Juliano Rizzo e Thai Duong;
In un attacco oracle di compressione, l'uso della compressione adattiva dei dati su una miscela di plaintext scelto e plaintext sconosciuto può causare variazioni sensibili al contenuto nella lunghezza del testo compresso, rilevabili anche se il contenuto del testo compresso stesso viene successivamente cifrato. Questo può essere usato negli attacchi di protocollo per rilevare quando il plaintext noto iniettato è anche solo parzialmente simile al contenuto sconosciuto di una parte segreta del messaggio, riducendo notevolmente la complessità della ricerca di una corrispondenza per il testo segreto. Gli attacchi CRIME e BREACH sono esempi di attacchi di protocollo che usano questo fenomeno.
L'attacco CRIME consente di recuperare i dati cifrati inviati da un client a un server sfruttando la lunghezza dei dati cifrati. Non consente di recuperare la chiave privata usata per cifrare il messaggio o la richiesta HTTP.
Molti articoli spiegano come funziona l'attacco CRIME, ma queste sono le migliori spiegazioni che ho trovato su internet:
Questo attacco non è davvero complesso; la parte davvero interessante è l'implementazione, che è un po' diversa dalla 'teoria'.
Controlliamo il metodo ingenuo come descritto nell'articolo: è un buon modo per capire come funziona:
L'attaccante può controllare le richieste inviate dal client (usando javascript, per esempio). L'obiettivo è recuperare il cookie segreto. L'attaccante invia più richieste come questa e controlla la lunghezza dei dati cifrati:
Poiché cookie=q corrisponde a cookie=quokkalight del cookie segreto, la lunghezza dei dati cifrati sarà la stessa e l'attaccante sa di aver trovato un byte.
Ma questo metodo fallisce alcune volte e non è affidabile, quindi useremo un altro metodo.
Prima inviamo una richiesta con il carattere che vogliamo trovare seguito da più caratteri che non possono essere trovati nella richiesta iniziale, come alcuni caratteri speciali: chr(i) + "#:/[@/&". Poi inviamo una seconda richiesta ma invertiamo il payload in questo modo: "#:/[@/&" + chr(i) e confrontiamo le due lunghezze. Se len(enc(req1)) < len(enc(req2)) allora abbiamo trovato un byte. Questo metodo si chiama two_tries ed è molto più affidabile:
L'attaccante ha trovato un byte!
if len(enc(request1)) < len(enc(request2)):
print("found byte")
Il metodo two_tries che ho implementato è completamente ricorsivo, ma perché? A volte può essere trovato più di un byte perché la compressione corrisponde a più pattern.
Prendiamo il segreto: cookie=quokkalight. Se eseguiamo l'algoritmo two_tries troveremo il seguente risultato:
result 1: cookie=quokie=quokie=quokie=quokie=quokie=
result 2: cookie=quokkalight
L'algoritmo deve seguire tutti i percorsi dell'albero per trovare tutte le possibili soluzioni. Possiamo vedere tutti i risultati come un albero che può essere rappresentato così:

La prova di concetto dell'attacco CRIME contro la modalità a flusso si trova nel file: CRIME-RC4-poc.py. Questa è un'implementazione in Python della spiegazione precedente.
python3 CRIME-RC4-poc.py
Demo completa e risultato:
Quando la modalità di cifratura CBC è usata con AES o DES, l'attacco non è semplice come con RC4. Poiché tutto è diviso in blocchi, l'attacco è un po' più complesso (non troppo).
Per esempio, supponiamo di usare AES in modalità CBC: il blocco sarà diviso con una lunghezza di 16 e un padding verrà aggiunto alla fine se len(data)%16 != 0.
Nella modalità CBC, è importante notare che il payload payload=rand produrrà una lunghezza di 16 e non di 12, poiché un padding verrà aggiunto alla fine dei dati prima della cifratura. Quindi il nostro attacco precedente non può funzionare.
Esempio:
In questo esempio, la lunghezza sarà sempre la stessa perché se aggiungiamo o rimuoviamo un byte, la lunghezza sarà sempre la stessa, cambierà solo il padding. L'attaccante vede solo i dati cifrati e non ha modo di conoscere il padding usando i dati cifrati.
Soluzione: giocare con le specifiche della modalità CBC, così la lunghezza del padding sarà 1 aggiungendo un valore casuale nella variabile GARB (nel parametro GET, poiché l'attaccante controlla i dati GET e POST).
Se il byte corrisponde a un pattern, la lunghezza sarà la stessa; se non corrisponde, la lunghezza sarà diversa.
Successivamente, dobbiamo solo usare lo stesso metodo spiegato nella parte RC4; aggiungiamo solo un passaggio prima.
adjust_padding() in modo da avere un padding di lunghezza 1two_tries_recursive() e possiamo trovare il FLAG segreto!python3 CRIME-cbc-poc.py
in arrivo molto presto...
\ /
\ _ /
----/_\----
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
| Richiesta | lunghezza |
|---|
| 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 |
| Richiesta per recuperare il byte q | lunghezza |
|---|
| 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 |
| blocco1 | blocco2 | blocco3 | lunghezza |
|---|
| 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 |
| blocco1 | blocco2 | blocco3 | blocco4 | lunghezza |
|---|
| 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 |