This is the third article in a three part series on JSON Web Tokens, that breaks down as follows:
What is a JWT – JSON Web Token?
This article gives you all the basics to understand how JSON Web Tokens work.
Hacking JWT – JSON Web Token (part 1)
This article explains how to use fuzzing techniques to try cracking a JWT’s secret.
And if you’re dealing with a token whose encryption password (or secret) you haven’t been able to crack, you’re not out of ammo just yet. This third article gives you a number of additional techniques, focused on manipulating the signing algorithm.
Using unsigned tokens
In some cases, you may be in luck and find yourself against an API that uses unsigned tokens. In this scenario, you won’t even need to resign a forged token.
To check if you are in this situation, the first thing you need to do is copy the JWT into jwt.io. Then look at the header section. If the algorithm key is set to none (
"alg": "none"), the token isn’t signed.
This means you can edit the payload section as you wish, modifying the existing keys or adding the keys you want.
Once you’re done, select the token and paste it back into the authorization header in the request you are using in Burp Suite or Postman to access your target endpoint. This should get you through.
Since the token is unsigned, you can even forget about the signature section of the JWT altogether and copy only the base64 encoded header and payload sections. Just make sure you include the periods at the end of both sections (yes, the trailing period at the end of the payload needs to be included too).
To give you a bit of context, the ‘none’ option is normally intended for debugging purposes and is supposed to be replaced by a proper signing algorithm when the app is pushed into production.
If a developer forgot to make the switch, you now have what it takes to exploit. Granted this scenario may not happen very often, but it’s definitely worth taking the time to try it out.
Bypassing the algorithm
Another scenario is that an API will use signed JWTs but will fail to verify the algorithm specified in the header section is the one that was originally set. In other words, the API will rely on the algorithm it reads in the token and will not look any further.
Edit the header section of the token, set the algorithm key to none
("alg": "none") and this may just get you through.
To do this, use the JSON Web Token Toolkit (install instructions here):
python3 jwt_tool.py <full_JWT_token> -X a
An example of this command would be:
python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gQWRhbXMiLCJpYXQiOjE1MTYyMzkwMjJ9.Qg3v3uHk-btWZAeOUjS4kC9ErBfG4KFheRN79Q_My_k -X a
This will generate a series of four token with the
alg key set to
You will notice that these tokens only have the header and payload sections and don’t use a signature section. Once again, don’t forget to include the final period when you copy and paste them into Burp Suite or Postman.
Now try sending a request to your target endpoint with each of these tokens and cross your fingers.
A more likely situation is when you come across a JWT that is signed with an RSA algorithm (check for
RS256 in the
alg field). This is an asymmetric algorithm that signs the token with a private key that is know only to the API provider and uses a public key that is openly available to verify the token.
What you should try to do is edit the header section of the token and select an HMAC algorithm (use
HS256 instead of
RS256). HMAC is a symmetric algorithm that uses the same key to sign and verify the token.
This means if you have the public key that is used to verify the JWT when the RSA algorithm is selected, you may be able to use this key to sign your forged token after you’ve select the HMAC algorithm.
Here again, no guarantee this will succeed but definitely worth a try.
Running a playbook scan
While you’re in the JSON Web Token Toolkit, you may also want to run a playbook scan, that will look for known JWT-related vulnerabilities in the app you’re targeting.
To do this, run the following command:
python3 jwt_tool.py -t <URL of the target app> -rc "jwt=<your token>" -M pb
For this scan to work, you will need to have Burp Suite running in the background, as this command requires a proxy to send its request to the target app. Also make sure Intercept is turned off in Burp Suite, as you don’t want to manually forward requests one by one…
An example of this command would be:
python3 jwt_tool.py -t http://192.168.1.26:8888 -rc "jwt=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0aW0xQGdtYWlsLmNvbSIsImlhdCI6MTY2ODM2MDI4OCwiZXhwIjoxNjY4NDQ2Njg4fQ.2dtyrHI68nsMx6q0RCB3UEIkVb6DcT7-We0dJxvMpJIujE6yshHvnU4ZfB9w-9iNyVL2yjQvE_dN706t0jbQ3g" -M pb
This will automate a number of checks.
If this doesn’t turn up anything interesting, you can try another JSON Web Token Toolkit scan with an extended set, using the following command:
python3 jwt_tool.py -t <URL of the target app> -rc "jwt=<your token>" -M at
As a final note, do keep in mind that a properly configured JSON Web Token is a hard nut to crack. So the techniques outlined in this article and the preceding one will only help you detect and exploit a weakly signed token. These weak tokens are out there. I wish you the best of luck in finding them.