I am testing an API that uses JWT for authentication. This JWT has a HS256 signature to prevent modification. I figured that if I determine the secret key used in this signature, I can create my own JWTs. How can I crack the secret key of a JWT signature?

I tried using jumbo john which does seem to have JWT support, but I can't get it to work:

$ ./john jwt.txt 
Using default input encoding: UTF-8
No password hashes loaded (see FAQ)

There is no JWT option in john --list=format.

up vote 4 down vote accepted

I ended up writing a little Python script that uses PyJWT to parse the JWT and check the signature.

There is also jwtbrute. I haven't tested it, but it seems to be a bit more efficient than my script because it does much work such as base64-decoding outside of the loop.

If you want to crack 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 hex instead of base64. Also, it is separated from the data with a # instead of .. I wrote a little script to do the conversion.

You also need a recent version of john. The version that comes with Kali didn'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
  • In your script you catch the exception ExpiredSignatureError. What significance does this have to guessing the secret? Even if it was an expired signature, couldn't we continue to attack the JWT for the secret? @sjoerd – Copy and Paste Sep 14 '16 at 17:46
  • Also if you could place comments on that script, it would help a lot. I was attempting to understand the flow, and reasoning for exceptions/etc. – Copy and Paste Sep 14 '16 at 18:04

Based on what you posted it appears that you are attacking the whole JWT, which I don't think JTR is smart enough to decode the base64, and separate out the signature.

How JWT work:

The have a header:

{ "alg": "HS256", "typ": "JWT" }

They have claims

{ "sub": "1234567890", "name": "John Doe", "admin": true }

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

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Testing against this is no good since brute force is trying to attack this entire string, which is not the secret.

Better bet:

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

You could brute force it I suppose, but if it's strong, you'll be sitting for an awfully long time.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.