Skip to content

Json Web Token attacks

Resources

https://github.com/Crypto-Cat/CTF/tree/main/web/WebSecurityAcademy/jwt

JSON web tokens (JWTs) are a standardized format for sending cryptographically signed JSON data between systems.

The server that issues the token typically generates the signature by hashing the header and payload. In some cases, they also encrypt the resulting hash.

  • As the signature is directly derived from the rest of the token, changing a single byte of the header or payload results in a mismatched signature.

  • Without knowing the server's secret signing key, it shouldn't be possible to generate the correct signature for a given header or payload.

JSON Web Signature (JWS) -

JSON Web Encryption (JWE) - The contents of the token are encrypted.

JWT signature verification attack

1. Server not verifying the signature

If the server doesn't verify the signature properly, there's nothing to stop an attacker from making arbitrary changes to the rest of the token.

For example, consider a JWT containing the following claims:

{ "username": "carlos", "isAdmin": false }

If the server identifies the session based on this username, modifying its value might enable an attacker to impersonate other logged-in users. Similarly, if the isAdmin value is used for access control, this could provide a simple vector for privilege escalation.

2. Accepting arbitrary signatures

JWT libraries typically provide one method for verifying tokens and another that just decodes them. For example, the Node.js library jsonwebtoken has verify() and decode().

Occasionally, developers confuse these two methods and only pass incoming tokens to the decode() method. This effectively means that the application doesn't verify the signature at all.

Payload can be changed with no limitation.

3. Accepting tokens with no signature

Otherwise called the "none" attack. JWTs can be signed using a range of different algorithms, but can also be left unsigned. In this case, the alg parameter is set to none, which indicates a so-called "unsecured JWT".

"alg" parameter can therefore be set to:

none
None
NONE
NoNE

Then, the attacker can be modify the payload.

Finally, the payload part must still be terminated with a trailing dot.

4. Brute-forcing secret keys

When implementing JWT applications, developers sometimes make mistakes like forgetting to change default or placeholder secrets.

jwt secrets payloads

https://github.com/wallarm/jwt-secrets/blob/master/jwt.secrets.list

hashcat -a 0 -m 16500 <jwt> <wordlist>

If you run the command more than once, you need to include the --show flag to output the results.

Once you have identified the secret key, you can use it to generate a valid signature. Use JWT Editor for that (tab Keys.)

Then, send you request to Repeater. In Repeater go to JSON Web Token tab, modify the payload and click on Sign. Select your signature.

5. JWT header parameter injections

According to the JWS specification, only the alg header parameter is mandatory. In practice, however, JWT headers (also known as JOSE headers) often contain several other parameters. The following ones are of particular interest to attackers.

  • jwk (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 matching kid parameter.

5.1. Injecting self-signed JWTs via the jwk parameter

The JSON Web Signature (JWS) specification describes an optional jwk header parameter, which servers can use to embed their public key directly within the token itself in JWK format.

How to perform the attack with Burpsuite:

1. With the extension loaded, in Burp's main tab bar, go to the JWT Editor Keys tab.

2. Generate a new RSA key.

3. Send a request containing a JWT to Burp Repeater.

4. In the message editor, switch to the extension-generated JSON Web Token tab and modify the token's payload however you like.

5. Click Attack, then select Embedded JWK. When prompted, select your newly generated RSA key.

6. Send the request to test how the server responds.

5.2. Injecting self-signed JWTs via the jku parameter

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. You can see an example of this below.

{ "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" } ] }`

JWK Sets like this are sometimes exposed publicly via a standard endpoint, such as /.well-known/jwks.json.

So a way to trick this validation is by creating our own set of RSA keys.

Then, have a server serving these keys.

Then, modify the payload of the JWT.

And finally, modify the head, by adding the kdi corresponding to our crafted RSA key, and a jkuparameter pointing to our server serving the keys. With this configuration we can use 'JWT Editor' in BurpSuite to sign the new crafted JWT.

5.3. Injecting self-signed JWTs via the kid parameter

Last update: 2024-05-02
Created: May 2, 2024 16:07:28