JWT
JSON web token.
JSON web tokens (JWTs) are a standardized format for sending cryptographically signed JSON data between systems. They can theoretically contain any kind of data, but are most commonly used to send information ("claims") about users as part of authentication, session handling, and access control mechanisms. Unlike with classic session tokens, all of the data that a server needs is stored client-side within the JWT itself.
A JWT consists of 3 parts: header.payload.signature
Attacks
The application doesn't verify the signature (but only decode).
Change
"alg": "none"in header (bypass filters using classic obfuscation techniques, such as mixed capitalization and unexpected encodings).
JWT header parameter injections
In header:
Only the
algheader parameter is mandatoryjwk(JSON Web Key) - Provides an embedded JSON object representing the key.jku(JSON Web Key Set URL) - Provides a URL from which servers can fetch a set of keys containing the correct key.kid(Key ID) - Provides an ID that servers can use to identify the correct key in cases where there are multiple keys to choose from. Depending on the format of the key, this may have a matchingkidparameter.
Injecting self-signed JWTs via the jwk parameter.
Ideally, servers should only use a limited whitelist of public keys to verify JWT signatures. However, misconfigured servers sometimes use any key that's embedded in the jwk parameter.
With JWT Editor extension:
Generate a new RSA key in JWT Editor Keys
Modify the token's payload in Burp Repeter in JSON Web Token tab
Click Attack, then select Embedded JWK and choose your newly generated RSA key.
Instead of embedding public keys directly using the jwk header parameter, some servers let you use the jku (JWK Set URL) header parameter to reference a JWK Set containing the key. When verifying the signature, the server fetches the relevant key from this URL.
A JWK Set is a JSON object containing an array of JWKs representing different keys.
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
},
{
"kty": "RSA",
"e": "AQAB",
"kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
"n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
}
]
}More secure websites will only fetch keys from trusted domains, but you can sometimes take advantage of URL parsing discrepancies to bypass this kind of filtering.
See URL Validation Bypass and Inconsistencies on URL Parser.
Verification keys are often stored as a JWK Set. In this case, the server may simply look for the JWK with the same kid as the token. However, the JWS specification doesn't define a concrete structure for this ID (it's just an arbitrary string of the developer's choosing). For example, they might use the kid parameter to point to a particular entry in a database, or even the name of a file.
If this parameter is also vulnerable to directory traversal, an attacker could potentially force the server to use an arbitrary file from its filesystem as the verification key.
In this case, an attacker could potentially point the kid parameter to a predictable, static file, then sign the JWT using a secret that matches the contents of this file.
ex. use use /dev/null (null key)
!!! If the server stores its verification keys in a database, the kid header parameter is also a potential vector for SQL injection attacks.
Algorithm confusion attacks
Generally, the JWT verification method is unique for all types of signatures, both symmetric and asymmetric. This method takes two parameters:
JWT tokens
Secret (symmetric encryption) or Public key (asymmetric encryption)
If developers assume that the JWT is always passed signed with an asymmetric encryption method such as RS256, and always pass the fixed public key to the verification method, a vulnerability may occur.
The attack consists of:
Obtain the server's public key
Standard endpoint:
/jwks.jsonor/.well-known/jwks.jsonExtract it from a pair of existing JWTs (jwt_forgery.py)
docker run --rm -it portswigger/sig2n <token1> <token2>
Convert the public key to a suitable format
With the extension loaded, in Burp's main tab bar, go to the JWT Editor Keys tab.
Click New RSA Key. In the dialog, paste the JWK that you obtained earlier.
Select the PEM radio button and copy the resulting PEM key.
Go to the Decoder tab and Base64-encode the PEM.
Go back to the JWT Editor Keys tab and click New Symmetric Key.
In the dialog, click Generate to generate a new key in JWK format.
Replace the generated value for the
kparameter with a Base64-encoded PEM key that you just copied.Save the key.
Create a malicious JWT with a modified payload and the
algheader set toHS256(symmetric encryption).Sign the token with HS256, using the public key as the secret.
In this way the verification method will be invoked with the token e the public key which however will be considered as secret, this is because the method defined in the header is a symmetric encryption. In other words it checks that the jwt token has been signed with the public key.
Last updated
Was this helpful?