14

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.

Sjoerd
  • 28,707
  • 12
  • 74
  • 102

3 Answers3

10

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
Sjoerd
  • 28,707
  • 12
  • 74
  • 102
  • 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
  • 1
    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
  • Did you update your script to make it more efficient? By the way, it is possible to crack the key of an RS256-signed JWT? (I noticed you only mentioned HS256 on your GitHub repository) – baptx Jun 07 '19 at 12:31
  • Hoi! Is this still current? With the latest version from GitHub it seems I can just dump a raw jwt token (no `#` or b64->hex conversion needed) into a file and run `./run/john /tmp/myjwtfile` – Luc Jun 09 '20 at 14:24
2

john has been supporting JWT natively as of this commit https://github.com/magnumripper/JohnTheRipper/commit/85aa7b3e3f8204360683ddc5ec9734bf793d07cf (2015).

So you can just put a JWT hash in the pw file without any changes nowadays, without having to do any transformations.

$ cat jwt.john 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYXNkZiJ9.GwJ7_ZrnpRLXXSBYzB9VkM4n7j2iSJEkdjhckeaXQ-U
$ john jwt.john
# Wait a few hours, then:
$ john --show jwt.john
thakis
  • 121
  • 2
1

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.

Shane Andrie
  • 3,780
  • 1
  • 13
  • 16