5

Is it possible to crack a JSON Web Token (JWT) using HS-256 algorithm with hashcat on a normal PC?

hashcat password.txt -m 16500 -a3

How can I calculate how much time it will take?

JWT first section for example eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

3 Answers 3

7

Hashcat allows you to crack multiple formats including the one you mentioned (JWT HS256) and the strength of it relies on the secret.

If the web application is using a strong secret, it can take a very long time to crack. You can optimize the probability of success by building custom dictionaries if you know any additional information about how the secret was generated.

As you do not know how far or close you are of the right answer, it is very hard to know how long will it take to crack it. You can get an estimate time of how long will it take to process a certain dictionary or certain rules.

Here is an example. Let's suppose we have the following JWT HS256:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNTc0ODM1MzE0LCJleHAiOjE1Nzc0MjczMTR9.GXWX72f5PQi4unRvF3eh6oPziUUr_iVxMyUL5NFlulU

JWT without secret

As you can see in the image. It says Invalid Signature, because we do not have the right secret. Now, we will try to crack it by using hashcat and john with the dictionary rockyou.txt.

Hashcat:

jwt_token.txt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNTc0ODM1MzE0LCJleHAiOjE1Nzc0MjczMTR9.GXWX72f5PQi4unRvF3eh6oPziUUr_iVxMyUL5NFlulU:9897

Hashcat Command:

┌──(galoget㉿hackem)-[~]
└─$ hashcat -m 16500 -a 0 jwt_token.txt /usr/share/wordlists/rockyou.txt 
hashcat (v6.2.5) starting

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 1 MB

Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 2 secs

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNTc0ODM1MzE0LCJleHAiOjE1Nzc0MjczMTR9.GXWX72f5PQi4unRvF3eh6oPziUUr_iVxMyUL5NFlulU:9897
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaW...NFlulU
Time.Started.....: Tue Jun 18 10:31:04 2022 (15 secs)
Time.Estimated...: Tue Jun 18 10:31:19 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 772.1 kH/s (1.77ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 11528192/14344385 (80.37%)
Rejected.........: 0/11528192 (0.00%)
Restore.Point....: 11526144/14344385 (80.35%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: 98io98io -> 989197
Hardware.Mon.#1..: Util: 72%

Started: Tue Jun 18 10:30:03 2022
Stopped: Tue Jun 18 10:31:20 2022

From the previous output we can see that the secret for this JWT was cracked and its value is: 9897.

John The Ripper:

Let's repeat the exercise with john. We will use the same input file from the previous command.

John Command:

┌──(galoget㉿hackem)-[~]
└─$ john jwt_token.txt -w=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA256
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 256/256 AVX2 8x])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
9897             (?)     
1g 0:00:00:03 DONE (2022-06-18 10:34) 0.2597g/s 2995Kp/s 2995Kc/s 2995KC/s 98992243..985824
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Again, the secret was found with this tool. Now, we can set the secret in the JWT website to verify the signature.

JWT with the cracked secret

We can see that the page shows: Signature Verified, meaning we can forge tokens with it.

For our example we will change the id. Let's assume the web application identifies the user by this id.

id = 2 --> John Doe (Low-privileged User)
id = 1 --> Administrator

By doing this change, we get the following token:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTc0ODM1MzE0LCJleHAiOjE1Nzc0MjczMTR9.inohRq76BxY5pU3wML1YgiLc6rhs0Dz9fsbZ2DvnOpc

Forged JWT with id 1

As you see in this example. The only thing preventing an attacker to take over any account is the secret. If the secret is a random string (Uppercase + lowercase characteres, numbers, symbols). The only mechanism to crack it will be via brute-force or by building a custom dictionary and even with this, it can take from a few seconds to a lot of years, depending on its value.

Hope it helps.

3

Can it be done in theory? Yes. You can easily format the JWT's signed parts, and signature, in the format HashCat expects, tell it the algorithm, and then set it to brute-forcing the key.

Is it remotely practical? Nope. Hashcat is meant for cracking passwords, human-memorable secrets that rarely have more than a 40-50 bits of entropy (and frequently far less). That's not what you're dealing with here.

JWTs are used for machine-to-machine communication, with no need or use for a human to memorize them; as such, they are usually using cryptographically secure random keys with at least 128 bits of entropy (if they aren't, that's probably a vulnerability). Each extra bit doubles the time taken. Each ten extra bits increases the time taken by roughly 1000x. With 80+ more bits than even a good password, it will take Hashcat over 1,000,000,000,000,000,000,000,000 times as long to brute force even just a 128-bit secret key than it would a typical password.

This is actually pretty clear if you think about how JWTs work. JWTs are used all over the web, and other parts of the Internet. They're stateless, meaning the server has no idea what JWTs it has or hasn't issued before. Instead, the server relies 100% on "is this signature valid?" to tell if the JWT was minted legitimately. If an attacker can take any valid JWT (such as one that they just got for signing in), plug it into Hashcat, and get the secret key back... well, that attacker could then forge a JWT claiming to be any user or have any level of privilege, and (re-)sign it with the trusted key. The server would trust that JWT, and the entire authentication and access control protections on the server could be bypassed. This doesn't happen, which logically implies that it's not that easy.

3
  • "This doesn't happen...", lol this happens all the time. People use weak passwords, and plenty of devs use really poor secrets for their JWTs, and hashcat is a great tool to crack those, just like it is for passwords. Jul 21, 2023 at 1:12
  • @XRBtoTheMOON Huh, do you have an example of that in production code (not e.g. a CTF)? I try never to underestimate people's capacity for bad security, but in 13 years of experience, the closest I've seen to that was hardcoded keys that were probably generated by keyboard smashing ("Simian key generation", a colleague joked); breakable in theory, but no evidence anybody had done so. Why would they? HMACs produced with a weak key look just as random as with a good one; an attacker would have to guess which site had a weak key, and spend a lot of resources trying to crack it.
    – CBHacking
    Jul 21, 2023 at 10:49
  • I haven't seen one in a while (but I also don't see HS256 as much anymore), but I've encountered it in production code several times while performing penetration tests (so can't give names). I don't waste time on a brute force, but it's so fast to check that I still always run them through a wordlist whenever I come across one. Jul 23, 2023 at 19:40
1

I assume you're talking about the HS256 algorithm, which uses HMAC-SHA-256. As outlined in this answer, it is possible to use hashcat to attack HMAC-SHA-256. You'll want to specify the HMAC value using the format specified in RFC 7515, which should be the first two base64-encoded segments with their period separator.

As that question outlines, the format is MAC:message. The MAC in this case should be hex encoded, so you'll need to base64-decode the third period-separated segment, hex-encode it, and then append a colon and the the first two base64-encoded segments with their period.

However, in my experience, people tend to issue JWTs and other tokens using randomly generated secrets from a CSPRNG with 128 or more bits of entropy. If the secret was generated that way, then it will be computationally infeasible to crack it. hashcat will only be effective if the secret is easily guessable, which is not typical.

4
  • How do you calculate and say the is possible to crach HA256 with hashcat? And HA512 is it possible too?
    – Kokomelom
    May 19, 2022 at 13:30
  • I've added a paragraph outlining how to put it in the proper form. You should also be able to handle the HS512 as well, since that's just HMAC-SHA-512. You'll have to change the parameters to specify you want that algorithm.
    – bk2204
    May 19, 2022 at 21:43
  • thank you about your reply. But I test today hashcat password.txt -m 16500 -a3 ?a?a?a?a?a?a?a?a and the estimated time was 300 years... you tell me that I can burn this JWT with normal PC :)
    – Kokomelom
    May 20, 2022 at 15:48
  • As I said in my answer, you can use hashcat. However, whether you can guess the HMAC secret is unknown, and in my experience, the secrets people tend to use will take much longer than 300 years to guess.
    – bk2204
    May 20, 2022 at 23:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .