JSON Web Tokens(JWT)

What is a JWT?

A JSON Web Token(JWT) is an encoded JSON object commonly used for Authorization as Access Tokens/ID Tokens and Information exchange. A JWT is base64-URL encoded. Therefore it can be decoded and should not contain sensitive data. To decode JWTs, you can use this web app https://jwt.io/.

A JWT is a string that consists of 3 parts delimited by a (.).

  • Header reveals the token type and the algorithm used to sign the token.

  • Payload encompasses the claims or information about the entity the token represents. There can be various types of claims(registered, public or private). You can read more about claims here.

  • Signature, which consists of the previous base64 encoded sections of the JWT and is signed with a secret.

Example JWT


Recently I was introduced to an incredible tool for attacking JSON Web Tokens(JWT)s. The tool is called jwt_tool. Jwt_tool has a handy wiki that breaks down how to use the tool and explains common misconfigurations/attacks and the basics of JWTs. Jwt_tool also proxies its traffic through Burp Suite by default if you have it running.

Common Attack

Now that we have an idea of the tooling we will use and are familiar with JWTs, let's dive into some common JWT misconfigurations/vulnerabilities. The application we are using for this demonstration is JuiceShop. JuiceShop is an intentionally vulnerable javascript application.

JuiceShop Landing Page

In JuiceShop, upon login, there is an API request sent to /rest/user/whoami. The response returns info about your user account. This request contains a token that includes the JWT for our user: sleepy-student.

Request With Valid JWT

Decode JWT using https://jwt.io:  

Decoded JWT

Decode JWT using jwt_tool:

python3 jwt_tool “<TOKEN>“ 


Decoded JWT


None Algorithm

In the previous section, I mentioned that a JWT consists of 3 sections. The final section is the signature. Suppose there was no signature. What would happen if the header contained "none" as the signing algorithm? 

Though it may seem counter-intuitive, it is required by standards specified in RFC7519 to implement the "none" algorithm option. This means that it is possible to modify tokens by replacing the algorithm value in the header with the "none" algorithm. Some libraries treat such tokens as signed, verified tokens. 

If the target is using such libraries, by using "alg":" none", it is possible for anyone to modify the tokens and the payload/claims. Without the signature to verify the token's integrity, a malicious user can tamper with the JWT and ultimately forge a valid token to gain access to another user's account or gain privileges they are not supposed to have. 

Let's demonstrate tampering with a token using jwt_tool. The arguments required to tamper with the token are -T for tamper, -Xa for exploit alg:none. Here is the entire command.

python3 jwt_tool.py <TOKEN> -T -X a 

Jwt_tool Tamper Token

After the algorithm is changed to "none" in the header, the signature must be removed. The last character in the JWT is a (.). Such a forged token structure would look like this:

<BASE64ENCODED_HEADER>.<BASE64ENCODED_PAYLOAD>.



Tamper Token Result

The decoded result shows that we modified the header to contain "alg":" none" but the claims are the same.

Decoded Tampered Token 

Our token for the target application uses alg:RSA256. We modify the token by changing the alg field in the header and removing the signature section from our JWT.

We can check if the server validates the token integrity by modifying the token and resending the API request. We can use jwt_tool to send these tampered tokens with the following command:


python3 jwt_tool.py -t "http://10.10.102.153/rest/user/whoami" -rc "token=<TOKEN>" -X a

The flag -t is used to specify the target, and -rc is used to set the request cookie. The target expects to receive the JWT as a "token" cookie. Similarly, we could have used -rh to send the token in the auth header as follows:

python3 jwt_tool.py -t "http://10.10.102.153/rest/user/whoami" -rh “Authorization: bearer token=<TOKEN>" -X a

However, this application is using the cookie for authentication, not the auth header. 

Alg:none Attack


The jwt_tool results indicate a successful attack. We can navigate over to Burp Suite to view the request/response.

Requests Alg:none Attack From jwt_tool

The figure above shows that we could successfully authenticate to the server using the modified JWT.

Now that we have a proof-of-concept working, we know our target will accept tokens we modified to use "alg":"none". Let's modify our claims.

First, we can try to forge a token for an account that does not exist. The command below now has a new flag -v for verbose, and -X has a value of n for null signature.

python3 jwt_tool.py -t "http://10.10.102.153/rest/user/whoami" -rc "token=<TOKEN" -T  -X n -v

We can modify the token claims, changing the username and email to invalid values.

Tampered Claims Fake User Account

Jwt_tool sends the attack with the tampered token and seems to receive a Successful response.

Tampered Claims Exploit

We can view the request/response from our jwt_tool attack in Burp Suite.

Result of Forged Token for Fake User Exploit


The response to our request with a forged token for a user that does not exist returns an empty user object. This makes sense because the user in our forged token does not exist so there is no user information to return. This is cool but does not have any real impact. Let's attempt to escalate our privileges.

While browsing the JuiceShop application, we notice a product review from an interesting user account.

Admin Review


First, we must modify our token claims and change sleepy-student@sleepy-student.co to admin@juice-sh.op. I will not modify the alg field here because the exploit will handle that in the next step.

python3 jwt_tool.py -T -v <TOKEN>

Forged Admin JWT

We will use this token generated by jwt_tool in our exploit with the following command:


python3 jwt_tool.py  -t "http://10.10.102.153/rest/user/whoami" -rc "token=<TOKEN>” -Xa 

Forge Admin Token Exploitation

 

The results from jwt_tool indicate the attack was successful. Now we can see the response in Burp Suite.

Forged Admin Token Request/Response


We have successfully forged a token for user admin@juice-sh.op.

Previous
Previous

What is Typosquatting?

Next
Next

I Wrote Vulnerable Code