githubEdit

JSON Web Tokens (JWTs)

JSON Web Token (JWT) is a format for transmitting cryptographically secure data. JWTs are typically used by web applications as a stateless session token.

in JWT-based authentication, the session token is replaced by a JWT containing user information. After verifying the token's signature, the server can retrieve all user info from the JWT claims sent by the user.

JWTs consist of three main parts: a header, a payload, and a signature, which are base64-encoded and separated by dot . characters:

<Base64_Header>.<Base64_Payload>.<Base64_Signature>
  • Header - contains metadata about the token itself, holding information that allows interpreting it such as the ecryption algorithm used to secure the JWT token

  • Payload - contains the actual data making up the token. This data comprises multiple standard (registered) claims or arbitrary, user-defined claims

  • Signature - computed based on the JWT's header, payload, and a secret signing key, using the algorithm specified in the header. The integrity of the JWT token is protected by the signature.

triangle-exclamation

Useful Tools and Resources


Attacking Signature Verification

The signature protects data within the JWT's payload. Without knowing the JWT's secret key, it's impossible to manipulate the token without invalidating it.

However, there are some misconfigurations in web applications that lead to improper signature verification, enabling us to manipulate the data within a JWT's payload.

Basic Misconfigurations

Case 1 - JWT signature verification is not in place

The first easy misconfiguration is when the web application does not check the JWT's integrity. If the web application is misconfigured to accept JWTs without verifying their signature, we can manipulate our JWT to escalate privileges or change our user data.

Case 2 - Signing algorithm set to None

Setting a manipulated JWT's algorithm to none implies that the JWT does not contain a signature, and the web application should accept it without computing one, which sometimes allows bypassing signature verification checks.

To forge a JWT with the none algorithm, we must set the alg-claim in the JWT's header to none

circle-exclamation

Algorithm Confusion

Description

Algorithm confusion is a JWT attack that forces the web application to use a different algorithm to verify the JWT's signature than the one used to create it.

If a web application uses an asymmetric algorithm like RS256, it signs JWTs with a private key and verifies them using a public key. However, if an attacker crafts a JWT that claims to use a symmetric algorithm like HS256, the situation changes, as it uses the same key for both signing and verification.

If the application naively trusts the alg field in the token header, it will attempt to verify the token using HS256 with whatever key it already has, which in this case is the public key.

Because the public key is, by definition, public, an attacker can sign a forged HS256 token using that public key, and the application will incorrectly accept it as valid.

triangle-exclamation

Performing the Attack

To execute the algorithm confusion attack, we need the public key used by the web application for signature verification, which you can get:

  • from the web application's certificate

  • from the web application's JKWS key set usually at https://example.com/.well-known/jwks.json

  • from the JWT itself

To gain the key from the JWT, get two valid JWTs from the web application (by logging in two times) and use rsa_sign2narrow-up-right

The tool may output multiple public key candidates based on the two JWTs you provided.

circle-check

Additionally, the tool automatically creates symmetric JWTs signed with the computed public key in different formats, which you can use to test for an algorithm confusion vulnerability.

If a token is accepted, you have confirmed the algorithm confusion vulnerability exists.

To forge a new token with edited claims, use the public key saved by the tool to a local file named filename_x509.pem within the docker container in CyberChef JWT Sign. Set the signing algorithm to HS256 and paste the public key into the Private/Secret key field.

triangle-exclamation

Cracking the JWT Secret

After gaining access to a valid JWT, it is possible to attempt to brute-force the signing secret to obtain it. JWT supports three symmetric algorithms based on potentially guessable secrets: HS256, HS384, and HS512. If your token uses one of those algorithms, you might be able to crack its secret key.

circle-check

To crack a JWT you can either use hashcat or jwt_tool:

Some wordlists other than rockyou.txt to crack JWTs are:

After finding the JWT's secret key, you can forge a new one using Cyberchefarrow-up-right JWT Sign or jwt_toolarrow-up-right


Exploiting JWT Standard Claims

Several standard claims might be leveraged by an attacker to exploit JWTs

jwk claim

circle-info

jwk contains information about the public key verification for asymmetric JWTs

If the web application is misconfigured to accept arbitrary keys provided in the jwk claim, you can forge a JWT, sign it with your private key, and then provide the corresponding public key in the jwk claim for the web application to verify the signature and accept the JWT.

To do that, first generate your keys using

Then, you can manually sign the new JWT using Cyberchef, or use the following script to generate the JWT (note: edit your payload accordingly)

Then run:


jku claim

circle-info

jku is similar to the jwk claim: it holds a URL that serves the key details rather than holding them directly.

When a web application does not correctly check this claim, it can be exploited using a nearly identical process to the jwk claim: instead of embedding the key details into it, the attacker hosts the key details on their web server and sets the JWT's jku claim to the corresponding URL.

triangle-exclamation

Also, the jwk claim can be exploited for blind GET based SSRF attacks!


kid claim

circle-info

The kid claim tells the server which public key to use to verify the JWT's signature by specifying the key's identifier. The web application will then look for a matching key in its key store.

Depending on how the server manages the value of the kid and checks for a corresponding key, injection vulnerabilities such as SQLi or Path traversal can occur.

If the kid allows a path traversal vulnerability, it is possible to arbitrarily edit a JWT by making the kid point to a file whose contents are known, then sign the JWT with a symmetric key whose value corresponds to the contents of this file.

The easiest idea is to redirect the kid claim's value to the /dev/null file: since this file is empty, the attacker can create a symmetric key whose value is an empty character string. Since the kid points to an empty value, the attacker can modify the JWT as he wishes and sign it with his empty symmetric key. Since the /dev/null file (and therefore the symmetric key) has an empty value, the JWT’s signature will be valid.