1

All About JWT Vulnerabilities

In this blog, we'll discuss JSON Web Tokens, the structure of JWT, and various vulnerabilities associated with JWTs
JWT Vulnerability Cyber Security Account Takeover
Tuhin Bose
September 27th 2023.
All About JWT Vulnerabilities

All About JWT Vulnerabilities

What is JWT?

As per jwt.io:

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

JWT (JSON Web Token) is widely used for authentication and authorization purposes. When a user enters their credential to sign in, the application verifies the credential, and if matched, issues a JWT to the user. Browser then sends the JWT to the server (usually through the Authorization header or cookies) for accessing protected resources.

Components of JWT

There are 3 parts of a JSON Web Token which are separated by dots (.):

  1. Header
  2. Payload
  3. Signature

Let's understand each of them one by one,

  1. Header: It is the first part of the JWT which generally consists of two parts - the type of the token and the algorithm used to sign the token. For example,
1{ 2 "alg": "HS256", 3 "typ": "JWT" 4} 5

This section is then encoded using base64Url which results in eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
Mostly, there are two algorithms used in JWT: RS256 (uses the private key to sign the JWT and public key for verifying) and HS256 (uses a secret key to sign and verify).

  1. Payload: It contains information about the user and additional entity attributes, called claims. There are 3 types of claims: reserved, public, and private claims. A typical payload will look like:
1{ 2 "iat":"1695023887", 3 "exp":"1695025687", 4 "email":"[email protected]", 5 "isAdmin":true 6} 7

Here iat and exp are issued at time (when the JWT is issued) and expiration time (when the JWT will expire) respectively.
This section is then encoded using base64Url to form the second part of the JWT. This results in eyJpYXQiOiIxNjk1MDIzODg3IiwiZXhwIjoiMTY5NTAyNTY4NyIsImVtYWlsIjoidHVoaW4uYm9zZUBidWdiYXNlLmluIiwiaXNBZG1pbiI6dHJ1ZX0

  1. Signature: This part is used to ensure that the JWT token hasn't been tampered with. The signature is created by taking the encoded header, encoded payload, a secret or a public key, and the algorithm specified in the header and then signing that data. For example, to create signature of JWT using the HS256 algorithm
1$header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; 2$payload = "eyJpYXQiOiIxNjk1MDIzODg3IiwiZXhwIjoiMTY5NTAyNTY4NyIsImVtYWlsIjoidHVoaW4uYm9zZUBidWdiYXNlLmluIiwiaXNBZG1pbiI6dHJ1ZX0"; 3$secretKey = "BugBase@$3cur!7y"; 4$signature = hash_hmac('sha256', "$header.$payload", $secretKey, true); 5

This results in W7F89xlBibTOQ_fVxUzm0KJDZwcIXbSkNDBYKcffAb0.
So the final JWT would be: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNjk1MDIzODg3IiwiZXhwIjoiMTY5NTAyNTY4NyIsImVtYWlsIjoidHVoaW4uYm9zZUBidWdiYXNlLmluIiwiaXNBZG1pbiI6dHJ1ZX0.W7F89xlBibTOQ_fVxUzm0KJDZwcIXbSkNDBYKcffAb0.

You can decode a JWT using jwt.io:
JWT.io

Vulnerabilities

Before proceeding with the common vulnerabilities present in JWT, we need a burp extension called "JSON Web Tokens". You can download it by navigating to the extender tab and searching for the name in the BApp Store.
Burp Extension

  • Signature not checked: Signature is used to ensure that the JWT token hasn't been tampered with. However, sometimes developers directly access the payload (data) without actually verifying the signature. In this case, we can simply modify the body using the burp extension (or through JWT.io).
  • None Algorithm Attack (CVE-2015-9235): JWTs can be signed using a range of different algorithms. It supports the none algorithm where any token would be considered valid if the signature is empty. For example, the token eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpYXQiOiIxNjk1MDIzODg3IiwiZXhwIjoiMTY5NTAyNTY4NyIsImVtYWlsIjoidHVoaW4uYm9zZUBidWdiYXNlLmluIiwiaXNBZG1pbiI6dHJ1ZX0. will be considered as valid. If you notice carefully, there is no signature part here and the header and body are just base64UrlEncoded. You can also try changing the algorithm to None/noNe/nOnE/NONE etc.
  • Weak secret: Sometimes developers use a weak secret key to sign the JWT token. In these cases, we can try bruteforcing the secret key using hashcat:
hashcat -a 0 -m 16500 <JWT-Token> <Path-to-Wordlist>

We can use rockyou.txt or any other popular wordlist for this.
Hashcat Output

  • Changing Algorithm: Suppose an application is designed to use RS256 algorithm in JWT. That means, there will be a private key to sign the JWT and a public key for verifying it. However, we can try changing the algorithm from RS256 to HS256 (in the header) and use their public key to verify the token. You can get the certificate of the web server using the following command:
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem 
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem

  • Vulnerable Kid: KID stands for Key ID. It is a header field in JWT which is generally used when there are multiple secret keys present to sign & verify different JWTs. KID helps to identify which key is used to sign a particular token. For example,
1{ 2 "alg": "HS256", 3 "typ": "JWT", 4 "kid": "68bf80e1-ecbb-4e36-a976-5eeb0d4d50fb" 5} 6

As you can imagine, the database must have a secret key corresponding to the id 68bf80e1-ecbb-4e36-a976-5eeb0d4d50fb. The application will fetch the secret key from the database and use it to verify the JWT token. Another example would be,

1{ 2 "alg": "HS256", 3 "typ": "JWT", 4 "kid": "http://localhost:8080/key1.txt" 5} 6

After receiving the JWT, the backend will fetch the key from the above URL and then use the key to sign/verify the token.

Now since the KID can be controlled by the user, there can be multiple vulnerabilities:

  1. Let's take the first example, where KID contains an id, and the application fetches the corresponding secret key of the id from the database. Here, the obvious thing that we can try is SQL Injection. We can modify the header & set it like the following:

SQLi

  1. Let's say you encountered an application where the KID contains the path of the secret key:
1{ 2 "alg": "HS256", 3 "typ": "JWT", 4 "kid": "/var/keys/key1.txt" 5} 6

It may possible that in the backend the application is passing the KID value directly into a command without proper sanitization:

1header = jwt.get_unverified_header(token) 2kid = header.get("kid") 3secret_key = subprocess.check_output([f"cat {kid}"], shell=True).decode().strip() 4decoded_payload = jwt.decode(token, secret_key, algorithms=["HS256"]) 5

Now, in this case, an attacker can simply achieve RCE by the following payload:

Command Injection

We can also try directory traversal attack if the KID contains path of the secret key. In this case, we will use a publicly available file to verify the token.

1{ 2 "alg": "HS256", 3 "typ": "JWT", 4 "kid": "../../../robots.txt" 5} 6


3. If the KID contains the URL of the secret key like this:

1{ 2 "alg": "HS256", 3 "typ": "JWT", 4 "kid": "http://localhost:8080/key1.txt" 5} 6

We can try changing the URL to our controlled domain so that the secret key is fetched from our server to verify the JWT.

KID Manipulation
If the application allows only RS256 algorithm, we can try to generate the public and private key by the following command:

ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub

How to Hunt These Vulnerabilities?
i. Look for an endpoint that returns some data about the user if the given JWT is correct, otherwise returns 401 or a similar response. Usually profile page is a good start.
ii. Manipulate JWT in the request and try each vulnerability (if applicable) one by one.

There are many more vulnerabilities related to JWT. We will discuss it in part 2 of this blog.

Automation

For automating most of the attacks, you can use jwt_tool. Check their README.md for installation and usage instructions.

References

[1] Hacktricks: https://book.hacktricks.xyz/pentesting-web/hacking-jwt-json-web-tokens
[2] Payloads All The Things: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/JSON%20Web%20Token
[3] JWT.io by Auth0: https://jwt.io/introduction

Table of Contents

  • All About JWT Vulnerabilities

Let's take your security
to the next level

security