diff --git a/src/pentesting-web/hacking-jwt-json-web-tokens.md b/src/pentesting-web/hacking-jwt-json-web-tokens.md index 0cab3c6965a..8db8172a410 100644 --- a/src/pentesting-web/hacking-jwt-json-web-tokens.md +++ b/src/pentesting-web/hacking-jwt-json-web-tokens.md @@ -27,6 +27,17 @@ python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291" You can also use the [**Burp Extension SignSaboteur**](https://github.com/d0ge/sign-saboteur) to launch JWT attacks from Burp. +### Practical JWT assessment workflow + +- **Scope the session control**: Pick a user-specific request (e.g., profile, billing). Remove cookies/headers one at a time until the request is rejected to isolate which token(s) actually gate authorization. +- **Locate JWTs in traffic**: They often sit in `Authorization: Bearer `, but also appear in custom headers or cookies. If Burp doesn’t highlight them, use Target → Site map → Engagement tools → Search with regex patterns such as: + - `[= ]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**: Use Burp **JWT Editor** or `python3 jwt_tool.py ` to read header/payload. Note `alg`, `exp`/token lifetime, and authn/authz-driving claims (`role`, `id`, `username`, `email`, etc.). +- **Signature enforcement sanity check**: Flip or delete a few bytes in the signature portion and replay. Acceptance implies missing signature validation and you can directly tamper payload claims. +- **Goal**: Modify payload claims to escalate privileges; every attack below aims to get the server to accept a tampered payload by abusing weak verification, weak secrets, or unsafe key selection. + ### Tamper data without modifying anything You can just tamper with the data leaving the signature as is and check if the server is checking the signature. Try to change your username to "admin" for example. @@ -54,6 +65,15 @@ Check if the token lasts more than 24h... maybe it never expires. If there is a [**See this page.**](../generic-hacking/brute-force.md#jwt) +If the header uses **HS256**, dump the token to a file and try offline cracking: + +```bash +python3 jwt_tool.py -C -d wordlist.txt +hashcat -a 0 -m 16500 jwt.txt /path/to/wordlist.txt -r /usr/share/hashcat/rules/best64.rule +``` + +Once the secret is recovered, load it as a symmetric key in Burp JWT Editor and re-sign modified claims. + ### Derive JWT secrets from leaked config + DB data If an arbitrary file read (or backup leak) exposes both **application encryption material** and **user records**, you can sometimes recreate the JWT signing secret and forge session cookies without knowing any plaintext passwords. Example pattern observed in workflow automation stacks: @@ -90,6 +110,8 @@ openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem ``` +Using Burp **JWT Editor**, import the RSA public key (from `/.well-known/jwks.json` or a PEM) and run **Attack → HMAC Key Confusion Attack** to automate the HS256 re-sign attempt. + ### New public key inside the header An attacker embeds a new key in the header of the token and the server uses this new key to verify the signature (CVE-2018-0114). @@ -133,6 +155,8 @@ python3 jwt_tool.py -I -hc kid -hv "../../dev/null" -S hs256 -p "" By targeting files with predictable content, it's possible to forge a valid JWT. For instance, the `/proc/sys/kernel/randomize_va_space` file in Linux systems, known to contain the value **2**, can be used in the `kid` parameter with **2** as the symmetric password for JWT generation. +A practical pattern for brittle file-system key loading is to generate an HS256 key with JWK `k` set to `AA==`, set `kid` to a traversal like `../../../../../../../dev/null`, and re-sign—some implementations treat the empty file as a valid HMAC secret and will accept forged tokens. + #### SQL Injection via "kid" If the `kid` claim's content is employed to fetch a password from a database, an SQL injection could be facilitated by modifying the `kid` payload. An example payload that uses SQL injection to alter the JWT signing process includes: @@ -175,6 +199,8 @@ 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. A URI pointing to a set of X.509 (a certificate format standard) public certificates encoded in PEM form. The first certificate in the set must be the one used to sign this JWT. The subsequent certificates each sign the previous one, thus completing the certificate chain. X.509 is defined in RFC 52807 . Transport security is required to transfer the certificates. @@ -281,6 +307,10 @@ The token's expiry is checked using the "exp" Payload claim. Given that JWTs are ### Tools +- [jwt_tool](https://github.com/ticarpi/jwt_tool) – decoding, claim/header tampering, offline secret cracking (`-C`) and semi-automated attack modes (`-M at`). +- [Burp JWT Editor](https://github.com/PortSwigger/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](https://hashcat.net/hashcat/) `-m 16500` – GPU-accelerated HS256 secret cracking after exporting JWTs to a wordlist. + {{#ref}} https://github.com/ticarpi/jwt_tool @@ -289,5 +319,8 @@ https://github.com/ticarpi/jwt_tool ## References - [n8n token forge chain – config+DB leak to JWT signing secret](https://github.com/Chocapikk/CVE-2026-21858) +- [Burp Suite – JWT Editor extension](https://github.com/PortSwigger/jwt-editor) +- [jwt_tool attack methodology](https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology) +- [Keys to JWT Assessments – TrustedSec](https://trustedsec.com/blog/keys-to-jwt-assessments-from-a-cheat-sheet-to-a-deep-dive) {{#include ../banners/hacktricks-training.md}}