JWT Attacks

Erik
Written by Erik on
JWT Attacks
  • JSON Web Tokens (JWT) are a format for sending cryptographically signed JSON data between systems.
  • In theory, they can contain any type of data, but are most commonly used for authentication, session management and access control mechanisms.
  • Unlike classic session tokens, all the data needed by a server is stored client-side within the JWT itself. This makes JWTs a popular choice for highly distributed websites where users need to interact seamlessly with multiple back-end servers.

Table of Contents

  1. JWT Headers
    1.1 JWK
    1.2 JKU
    1.3 KDI
  2. JWT Signature
  3. Unverified signature
  4. Faulty signature verification
  5. Weak signature key
  6. Jwk header injection

A JWT consists of 3 parts:

  • Header (Contains metadata about the type of token and the cryptographic algorithms used to secure its contents)
  • Payload (Contains verifiable security statements, such as the identity of the user and the permissions they are allowed)
  • Signature (Is used to validate that the token is trustworthy and has not been tampered with)

Each of them is separated by a dot, as shown in the following example:

JWTexample


Headers JWT

JWK

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

Example of the JWK header:

{
   "kid":"ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
   "typ":"JWT",
   "alg":"RS256",
   "jwk":{
      "kty":"RSA",
      "e":"AQAB",
      "kid":"ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
      "n":"yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
   }

JKU

Instead of incorporating public keys directly using the jwk header parameter, some servers allow you to use the jku header parameter (JWK Set URL) to reference a JWK Set containing the key. When verifying the signature, the server obtains the relevant key from this URL.

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

KDI

The header of a JWT can contain a kid parameter (key ID), which helps the server identify which key to use when verifying the signature.

Example of the KDI header:

{
    "kid": "7a0faa13-f336-49ff-9a3b-3cda86ed3eab",
    "alg": "RS256"
}

JWT Signature

The server issuing the token usually generates the signature by hashing the header and payload.

This process involves a secret key. Without knowing this key, it is not possible to generate a valid signature for a given header and payload.

This provides a mechanism for servers to verify that none of the data has been tampered with since the token was issued, because any change to the header or payload would mean that the signature no longer matches.

Knowing the key that generates the signature we can generate tokens to our liking, this would be a problem because we can create a token for example as an administrator.


Bypass of JWT authentication through unverified signature

The session cookie is a JWT token. cookie-LAB1

With a burpsuite extension we can easily decode the tokens. We can see that the token contains which user it refers to in the session. JWTdecoded-LAB1

{
  "kid": "55b9956e-6cf5-4010-9423-eb7a9746a5d7",
  "alg": "RS256"
},
{
  "iss": "portswigger",
  "sub": "wiener",
  "exp": 1655146551
}

If the web application has not properly configured the token system, it is possible that it does not validate the signature that generates them, thus causing that we can modify the content of the token to our liking making useless the JWT token system.

Taking advantage of this configuration failure, we change the user to administrator jwtdecodedadmin-LAB1

{
  "kid": "55b9956e-6cf5-4010-9423-eb7a9746a5d7",
  "alg": "RS256"
},
{
  "iss": "portswigger",
  "sub": "administrator",
  "exp": 1655146551
}

We apply the token to the session and reload the account panel.

adminprofile-LAB1


Bypass of JWT authentication through verification of faulty signature

The token system has a bug in the signature configuration that allows modifying the header so we can change the algorithm by which the signature is built and create again a token to our liking.

JWT unmodified:

JWTnormal-LAB2

Matches our account: Wiener

normalaccount-LAB2

We modified the HEADER of the algorithm to none to make the signature completely useless and thus change the user name to administrator.

The token does not contain the signature part now, since the algorithm value we have modified is now null.

admintoken-LAB2

Account referenced by the token name modified above due to the verification failure.

adminpanel-LAB2


Bypass of JWT authentication using a weak signature key.

When the key used to generate the signature is weak, we can do a dictionary attack to try to guess it and thus generate our own valid tokens using a valid signature because we have the key.

We can see that JWT tokens are used in user sessions.

normaluser-LAB3

Without the key that generates the signature we cannot create new tokens. We proceed to crack the signature by dictionary attack.

John The reapper cracking the token. We write the token in a file and crack it with john or hashcat.

john-LAB3

The key that generates the token signature is secret1.

We proceed to generate the token for an administrator session.

When we indicate that the key is secret1 it indicates that the signature is valid, which indicates that the token that we have created as administrator user is valid in the application.

keysignature-LAB3

We apply it with cookie and it authenticates us with the account to which the token belongs, in this case we indicate the administrator user.

admin-LAB3


Bypass of JWT authentication through jwk header injection

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

This is our user’s token.

tokenusernormal-LAB4

We can inject in the header a key generated by us, since the configuration of how token headers are interpreted is misconfigured and allows injecting headers.

Ideally, servers should only use a limited whitelist of public keys to verify JWT signatures. However, misconfigured servers sometimes use whatever key is embedded in the jwkparameter.

Thanks to this we can include in the header the jwk parameter which is used to embed the public key directly, this allows us to have control over the rest of the token since now the public key is the one we have control over.

We proceed to embed the header to modify the token to a privileged user. And generate the key thanks to the JWT Editor Keys extension of burpsuite.

generatekey-LAB4

Once we have the key we apply it in the token in the header part. We apply the JWK header and also change the user parameter to refer to the administrator user.

Click on the attack button and embedded JWK to create the signature with the key we have created.

attackapplykey-LAB4

option-LAB4

The token structure would look like this:

tokenfinal-LAB4

If we forward the request with the new token we see that it has been validated and now belongs to the administrator user.

adminpannel-LAB4


Good resources:
Credits
Erik

Erik

Hi! Im Erik I love computer security and in my spare time I do bug bounty or research.
Every day I try to learn something new, no matter how small it is.