JWT — Burpsuite Web Academy Walkthrough
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. This makes JWTs a popular choice for highly distributed websites where users need to interact seamlessly with multiple back-end servers
Working with JWTs in Burp Suite
https://portswigger.net/web-security/jwt/working-with-jwts-in-burp-suite
JWT authentication bypass via unverified signature
This lab uses a JWT-based mechanism for handling sessions. Due to implementation flaws, the server doesn’t verify the signature of any JWTs that it receives.
To solve the lab, modify your session token to gain access to the admin panel at /admin
, then delete the user carlos
.
In Burp, go to the Proxy > HTTP history tab and look at the post-login GET /my-account
request. Observe that your session cookie is a JWT
Double-click the payload part of the token to view its decoded JSON form in the Inspector panel. Notice that the sub
claim contains your username. Send this request to Burp Repeater.
admin panel is only accessible for administrator
Unfortunately, the Inspector cannot currently decode both the header and payload at the same time. You need to select either one or the other.
truncate the payload and decode one by one
eyJraWQiOiI5ODVkN2MxYS0yYWYwLTRlOWQtODQ5OC1kOTQzMDkwMTRiZmYiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY4MDIzMzYyNX0.FBPPlL26okr2sfyRytStPXyMnAYJ5QQ0A6wRudNvxvjlCSH423pcp1EaWytKJXiIi2DpU4r-cG4LCMCvCahg5eAPSfJJj-mPUZycAkGblotoWQK0A6iBF4bt0eguQTROlIMN3FQWM5bacaDd12jpYWyXsPQJRgKecOKEkADkqHC_gLL3mrxwnzLefbjxxBH2A3uXgdqrE3TLBNS8CGzWIbU44DfZeBwAYph7uNSfagqG-m4bXlruVfuaOOog9L06pYDXXwoiP7pGasliM4U6D8mXaQ4GfJ_kj8q-7nw8Yytd-FGSEtLQotO56DcH0ZBxFvjRCpoub6qOHZ19jWFKgQ
(change the sub to administrator )
and access /admin
Then we can access admin panel , however we can not delete it from the web interface because we are still logged in as wiener
Change the request to /admin/delete?username=carlos in burpsuite with the modified JWT , and we can delete it from burp
JWT authentication bypass via flawed signature verification
go to the Proxy > HTTP historytab and look at the post-login GET /my-account
request. Observe that your session cookie is a JWT
Use same methods as previous exercise to inspect JWT token and change the sub to adminitrator
Path to admin
But failed to authorize this time
send the cookie to Json web token
change “alg” to none , change “sub” to administrator , and remove the signature
(No signature attack)
then we can access admin panel
delete carlos with request /admin/delete?username=carlos
JWT authentication bypass via weak signing key
This lab uses a JWT-based mechanism for handling sessions. It uses an extremely weak secret key to both sign and verify tokens. This can be easily brute-forced using a wordlist of common secrets.
To solve the lab, first brute-force the website’s secret key. Once you’ve obtained this, use it to sign a modified session token that gives you access to the admin panel at /admin
, then delete the user carlos
.
Part1 Brute force with hashcat
JWT attacks | Web Security Academy
Wordlist
jwt-secrets/jwt.secrets.list at master · wallarm/jwt-secrets
Intercept the request after log in
copy the JWT and bruteforce secret
eyJraWQiOiI0YmQ3N2RkMC02NDNhLTQzNTUtYmVmYS0zYmMyNzk2ZWViZmYiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY4MDIzNjc1Nn0.HmjH8F8r1SZHXR5wrLgjqp9nd1oLPgQhovTiJR0Ok1I
hashcat -a 0 -m 16500 jwt jwt.secrets.list
the secret key is secret1
Part 2 — Generate a forged signing key
- Using Burp Decoder, Base64 encode the secret that you brute-forced in the previous section.
- In Burp, go to the JWT Editor Keys tab and click New Symmetric Key. In the dialog, click Generate to generate a new key in JWK format. Note that you don’t need to select a key size as this will automatically be updated later.
- Replace the generated value for the
k
property with the Base64-encoded secret. - Click OK to save the key.
Part 3 Modify and sign the JWT
- Go back to the
GET /admin
request in Burp Repeater and switch to the extension-generated JSON Web Token message editor tab. - In the payload, change the value of the
sub
claim toadministrator
- At the bottom of the tab, click
Sign
, then select the key that you generated in the previous section. - Make sure that the
Don't modify header
option is selected, then clickOK
. The modified token is now signed with the correct signature.
- Send the request and observe that you have successfully accessed the admin panel.
- In the response, find the URL for deleting Carlos (
/admin/delete?username=carlos
). Send the request to this endpoint to solve the lab.
JWT authentication bypass via jwk header injection
This lab uses a JWT-based mechanism for handling sessions. The server supports the jwk
parameter in the JWT header. This is sometimes used to embed the correct verification key directly in the token. However, it fails to check whether the provided key came from a trusted source.
To solve the lab, modify and sign a JWT that gives you access to the admin panel at /admin
, then delete the user carlos
.
Intercept a request on Get /account
The admin panel is only accessible for administrator
- Go to the JWT Editor Keys tab in Burp’s main tab bar.
- Click New RSA Key.
- In the dialog, click Generate to automatically generate a new key pair, then click OK to save the key. Note that you don’t need to select a key size as this will automatically be updated later.
- Go back to the
GET /admin
request in Burp Repeater and switch to the extension-generatedJSON Web Token
tab. - In the payload, change the value of the
sub
claim toadministrator
.
- At the bottom of the JSON Web Token tab, click Attack, then select Embedded JWK. When prompted, select your newly generated RSA key and click OK.
- In the header of the JWT, observe that a
jwk
parameter has been added containing your public key. - Send the request. Observe that you have successfully accessed the admin panel.
Delete carlos with GET /admin/delete?username=carlos
JWT authentication bypass via jku header injection
This lab uses a JWT-based mechanism for handling sessions. The server supports the jku
parameter in the JWT header. However, it fails to check whether the provided URL belongs to a trusted domain before fetching the key.
To solve the lab, forge a JWT that gives you access to the admin panel at /admin
, then delete the user carlos
Instead of embedding public keys directly using the jwk
header parameter, some servers let you use the jku
(JWK Set URL) header parameter to reference a JWK Set containing the key. When verifying the signature, the server fetches the relevant key from this URL.
Intercept request of get /account
Part 1 — Upload a malicious JWK set
- Go to the JWT Editor Keys tab in Burp’s main tab bar.
- Click New RSA Key.
- In the dialog, click Generate to automatically generate a new key pair, then click OK to save the key. Note that you don’t need to select a key size as this will automatically be updated later.
- In the browser, go to the exploit server.
Replace the contents of the Body section with an empty JWK Set as follows:
{
"keys": [
]
}
- Back on the JWT Editor Keys tab, right-click on the entry for the key that you just generated, then select Copy Public Key as JWK.
- Paste the JWK into the
keys
array on the exploit server, then store the exploit. The result should look something like this:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "42e778bb-3fdd-4632-85cf-0399b9179eaa",
"n": "p-eWG9z7cvlFN4tiNYIVxHOaY9kAm_mKQU3ZURU5R4ML4qF6-3SrYGVMT5xhi0RJ0GEu4wROpbjzJai9qSoUWjMbrEiy2LqBZNsdY8UrO7iSYiCJfLuQkLU2IiQXhJ5sgDeFGIeInEQoZYo7iN_kQzVcemU1FOCHQDxC1iV5MHu8DF1I5WCeHzpJFRZmCz4v63WnxrGjMI3vHoMSAuQuHFV_ukueNYuSD8Lx5N-rZQpnJ7Gi0NxdEleE0dxBckqJUG6FgYCQGrlrb68QJlbn1Hoz3XeOID2NS5cmTgzksQXyKqHSpgCavH0FdG5p_Q6VquyPPVBEbxxMKqJOoA_qOQ"
}
]
}
file name : /.well-known/jwks.json
Part 2 — Modify and sign the JWT
Go to JSON Web token editor
- In the header of the JWT, replace the current value of the
kid
parameter with thekid
of the JWK that you uploaded to the exploit server.
- Add a new
jku
parameter to the header of the JWT. Set its value to the URL of your JWK Set on the exploit server.
- In the payload, change the value of the
sub
claim toadministrator
.
- At the bottom of the tab, click Sign, then select the RSA key that you generated in the previous section.
- Make sure that the Don’t modify header option is selected, then click OK. The modified token is now signed with the correct signature.
- Send the request. Observe that you have successfully accessed the admin panel.
- In the response, find the URL for deleting Carlos (
/admin/delete?username=carlos
). Send the request to this endpoint to solve the lab.
JWT authentication bypass via kid header path traversal
This lab uses a JWT-based mechanism for handling sessions. In order to verify the signature, the server uses the kid
parameter in JWT header to fetch the relevant key from its filesystem.
To solve the lab, forge a JWT that gives you access to the admin panel at /admin
, then delete the user carlos
Servers may use several cryptographic keys for signing different kinds of data, not just JWTs. For this reason, the header of a JWT may contain a kid
(Key ID) parameter, which helps the server identify which key to use when verifying the signature.
Verification keys are often stored as a JWK Set. In this case, the server may simply look for the JWK with the same kid
as the token. However, the JWS specification doesn't define a concrete structure for this ID - it's just an arbitrary string of the developer's choosing. For example, they might use the kid
parameter to point to a particular entry in a database, or even the name of a file.
If this parameter is also vulnerable to directory traversal, an attacker could potentially force the server to use an arbitrary file from its filesystem as the verification key.
{
"kid": "../../path/to/file",
"typ": "JWT",
"alg": "HS256",
"k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc"
}
Part 1 — Generate a suitable signing key
- Go to the JWT Editor Keys tab in Burp’s main tab bar.
- Click New Symmetric Key.
- In the dialog, click Generate to generate a new key in JWK format. Note that you don’t need to select a key size as this will automatically be updated later.
- Replace the generated value for the
k
property with a Base64-encoded null byte (AA==
). Note that this is just a workaround because the JWT Editor extension won't allow you to sign tokens using an empty string.
Null Byte : AA==
- Click OK to save the key.
Modify and sign the JWT
- Go back to the
GET /admin
request in Burp Repeater and switch to the extension-generated JSON Web Token message editor tab. - In the header of the JWT, change the value of the
kid
parameter to a path traversal sequence pointing to the/dev/null
file:../../../../../../../dev/null
- In the JWT payload, change the value of the
sub
claim toadministrator
.
- At the bottom of the tab, click Sign, then select the symmetric key that you generated in the previous section.
- Make sure that the Don’t modify header option is selected, then click OK. The modified token is now signed using a null byte as the secret key.
- Send the request and observe that you have successfully accessed the admin panel.
- In the response, find the URL for deleting Carlos (
/admin/delete?username=carlos
). Send the request to this endpoint to solve the lab.
JWT authentication bypass via algorithm confusion
This lab uses a JWT-based mechanism for handling sessions. It uses a robust RSA key pair to sign and verify tokens. However, due to implementation flaws, this mechanism is vulnerable to algorithm confusion attacks.
To solve the lab, first obtain the server’s public key. This is exposed via a standard endpoint. Use this key to sign a modified session token that gives you access to the admin panel at /admin
, then delete the user carlos
.
Algorithm confusion attacks | Web Security Academy
The following pseudo-code shows a simplified example of what the declaration for this generic verify()
method might look like in a JWT library:
function verify(token, secretOrPublicKey){
algorithm = token.getAlgHeader();
if(algorithm == "RS256"){
// Use the provided key as an RSA public key
} else if (algorithm == "HS256"){
// Use the provided key as an HMAC secret key
}
}
Problems arise when website developers who subsequently use this method assume that it will exclusively handle JWTs signed using an asymmetric algorithm like RS256. Due to this flawed assumption, they may always pass a fixed public key to the method as follows:
publicKey = <public-key-of-server>;
token = request.getCookie("session");
verify(token, publicKey);
In this case, if the server receives a token signed using a symmetric algorithm like HS256, the library’s generic verify()
method will treat the public key as an HMAC secret. This means that an attacker could sign the token using HS256 and the public key, and the server will use the same public key to verify the signature
Part 1- Obtain the server’s public key
Go to /jwks.json
and observe that the server exposes a JWK Set containing a single public key.
copy the key array
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "6fb522ca-81e0-4aa9-9228-ffe6d4e51a68",
"alg": "RS256",
"n": "wXF_jqFn35gmHzF43gG4KwJAs-ZXhJffZ4O8-JBwsqXjg55_ATjOp10k498yE8B7h3YHuKhHvRuptsO23EbcQjSQnrDEkw2yb0TCIJ0gjIdvo9GZYiq6518M9Scig_pttfoiNNhakCCdOdkVuM2p4v_IZ3K1z1sn5EYKQ0MrBDqo2WEp1JowgjKYi54EZ47JTItYpXZN8Oc5v7gxTscvh5KxIpg9wFCHpcyVeVToKMMOt5sU73negVVd1OUAy2LRcT9U8USbce1MlbBWBTew50fLBusDlCZPjU1WkIy6Fc-Ec6kHA0hm1u1qm831Kcw-S60fSJlOMWmAvb4jl67EnQ"
}
Part 2 — Generate a malicious signing key
- In Burp, go to the JWT Editor Keys tab in Burp’s main tab bar.
- Click New RSA Key.
- In the dialog, make sure that the JWK option is selected, then paste the JWK that you just copied. Click OK to save the key.
- Right-click on the entry for the key that you just created, then select Copy Public Key as PEM.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXF/jqFn35gmHzF43gG4
KwJAs+ZXhJffZ4O8+JBwsqXjg55/ATjOp10k498yE8B7h3YHuKhHvRuptsO23Ebc
QjSQnrDEkw2yb0TCIJ0gjIdvo9GZYiq6518M9Scig/pttfoiNNhakCCdOdkVuM2p
4v/IZ3K1z1sn5EYKQ0MrBDqo2WEp1JowgjKYi54EZ47JTItYpXZN8Oc5v7gxTscv
h5KxIpg9wFCHpcyVeVToKMMOt5sU73negVVd1OUAy2LRcT9U8USbce1MlbBWBTew
50fLBusDlCZPjU1WkIy6Fc+Ec6kHA0hm1u1qm831Kcw+S60fSJlOMWmAvb4jl67E
nQIDAQAB
-----END PUBLIC KEY-----
- Use the Decoder tab to Base64 encode this PEM key, then copy the resulting string.
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3WEYvanFGbjM1Z21IekY0M2dHNApLd0pBcytaWGhKZmZaNE84K0pCd3NxWGpnNTUvQVRqT3AxMGs0OTh5RThCN2gzWUh1S2hIdlJ1cHRzTzIzRWJjClFqU1FuckRFa3cyeWIwVENJSjBnaklkdm85R1pZaXE2NTE4TTlTY2lnL3B0dGZvaU5OaGFrQ0NkT2RrVnVNMnAKNHYvSVozSzF6MXNuNUVZS1EwTXJCRHFvMldFcDFKb3dnaktZaTU0RVo0N0pUSXRZcFhaTjhPYzV2N2d4VHNjdgpoNUt4SXBnOXdGQ0hwY3lWZVZUb0tNTU90NXNVNzNuZWdWVmQxT1VBeTJMUmNUOVU4VVNiY2UxTWxiQldCVGV3CjUwZkxCdXNEbENaUGpVMVdrSXk2RmMrRWM2a0hBMGhtMXUxcW04MzFLY3crUzYwZlNKbE9NV21BdmI0amw2N0UKblFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
- Go back to the JWT Editor Keys tab in Burp’s main tab bar.
- Click New Symmetric Key. In the dialog, click Generate to generate a new key in JWK format. Note that you don’t need to select a key size as this will automatically be updated later.
- Replace the generated value for the k property with a Base64-encoded PEM that you just created.
- Save the key.
Part 3 — Modify and sign the token
Go back to the GET /admin
request in Burp Repeater and switch to the extension-generated JSON Web Token tab.
In the header of the JWT, change the value of the alg
parameter to HS256
.
In the payload, change the value of the sub
claim to administrator
.
At the bottom of the tab, click Sign, then select the symmetric key that you generated in the previous section.
Make sure that the Don’t modify header option is selected, then click OK. The modified token is now signed using the server’s public key as the secret key.
Send the request and observe that you have successfully accessed the admin panel.
In the response, find the URL for deleting Carlos (/admin/delete?username=carlos
). Send the request to this endpoint to solve the lab.
JWT authentication bypass via algorithm confusion with no exposed key
This lab uses a JWT-based mechanism for handling sessions. It uses a robust RSA key pair to sign and verify tokens. However, due to implementation flaws, this mechanism is vulnerable to algorithm confusion attacks.
To solve the lab, first obtain the server’s public key. Use this key to sign a modified session token that gives you access to the admin panel at /admin
, then delete the user carlos
.
Algorithm confusion attacks | Web Security Academy
Part 1 — Obtain two JWTs generated by the server
log in and intercept with burpsuite , copy the JWT session cookie
log out and log in again , copy the new JWT session cookie
eyJraWQiOiJjMTE0Y2ZlYi00YjE0LTQyYTktOGVlYS1kM2QyMmY3MDc3MDMiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY4MDY3NzM0OH0.i1xQpc5vaL9FeWInchoJqmGwiyh7GZE_SHiHi8_u4c81UoIe92T7-0ilbUL4hYA21FN7CKjf595hKB_j7Wl4ZOS8FvhcjSto5wVPT7EXri_JQFVGMPjo-IwbccvhSRE-fZBGkvzEOqMoAviB3EtHXQkDHJR5EfEHAbghf1T-M_fmFKDgWJYeUEH1TNLxEKGEiFSCouaDF_g-BftavERuiu1Bfk3dusz2zFY1fW2fAHs1rjhgBh3lkqtW1DcqCnH4ktWiVKCufOJ9j8a34BtsiFtFhSh3GT8euJ5IlvFFnmG0qSsv8p_LT0V7zhVy5pZZExTCiz1WmQ1O4haen4c20g
eyJraWQiOiJjMTE0Y2ZlYi00YjE0LTQyYTktOGVlYS1kM2QyMmY3MDc3MDMiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY4MDY3NzQ5M30.TgJBB1A5OmVfEjXWa06LlBZ70FRsthhVOWWSoKB15RIl_YcdaCLkv0X7wXCCJ2ZFNJFQYi2w9t6Tqm1K1gOHE-A9qbtKMXft5dB0mFfk3vH71uAIZDOgOHP9zuA43R4O08pT8PzbpPGJ6u-orCXw9ErhOFolmYOIE3-AtQnkUBFfHPzI5U6mVBVdxNAbQ9W8wzGttyutgt9C8U6b30Um0cx8V7e7L4mY3QYFbUqSTQ6R_XwSE1L5FLYNk9PU_E-tfnGjtqBKtRL11yYTtLgWN15cYwGsaxcXtwZYfskN1sFyiupmqTGoLS1jkxyo4qn5g33FRrCGBE6MdYKxI4hYRw
Part 2 — Brute-force the server’s public key
- In a terminal, run the following command, passing in the two JWTs as arguments.
docker run --rm -it portswigger/sig2n <token1> <token2>
- Note that the first time you run this, it may take several minutes while the image is pulled from Docker Hub.
docker pull portswigger/sig2n
Notice that the output contains one or more calculated values of n
. Each of these is mathematically possible, but only one of them matches the value used by the server. In each case, the output also provides the following:
- A Base64-encoded public key in both X.509 and PKCS1 format.
- A tampered JWT signed with each of these keys.
Copy the tampered JWT from the first X.509 entry (you may only have one).
eyJraWQiOiI1NTk4NTk3My0xMGVjLTQwMmMtOTNkYi01OGQzNjFkOTIxMzkiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjgwNzYzMjE5fQ.DHmRV3arYdlx6mv-S48DRwDVH5qdGi4JbYM5H68HaoE
Go back to your request in Burp Repeater and change the path back to /my-account
.
Replace the session cookie with this new JWT and then send the request.
- If you receive a 200 response and successfully access your account page, then this is the correct X.509 key.
- If you receive a 302 response that redirects you to
/login
and strips your session cookie, then this was the wrong X.509 key. In this case, repeat this step using the tampered JWT for each X.509 key that was output by the script.
Part 3 — Generate a malicious signing key
- From your terminal window, copy the Base64-encoded X.509 key that you identified as being correct in the previous section. Note that you need to select the key, not the tampered JWT that you used in the previous section.
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFwZ3lDVWZpVTFCSW5ocDBrU0dlMgpCV0poOEV1WEliQlhBM2ZONnpjeThHdnpUVTFwNm9GZE5BeUl5RFNvTlpRd05NTzFQVUJ5Y3V2US80RlVxdWl4CkdWUFhZS0JJcXkvREtVYStaMkxrd01aVjdvRFY2Nk1obFJjb1RrLzdsbkpLelR5Vm1oSlpNN2lBY2poRXlwUWgKRkZmc0l2TmJpVUNxR2trQUY5QWFvakJNT2ozL25DWWZjSldXVzBZVEFCR1B6emVWUFNFa1o4T2hOZWdNOVkreQpyM3RQWEFNYjdzcGdRZHExZGV4UkZiSlU5SW5OUlEyNlZMR0QvdTVscDBkUTIrelpKUlFPVTNScjZIZVZGNTlaCjlaT1BsbFh6Qko1RXJVVmZpbXlmNVY5L0NnNFZ5UkQ5WmxxUFBDREhWM2ZkNWkxZ29TcUFYRUlEOFl3NDdQQ1QKUFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
In Burp, go to the JWT Editor Keys tab and click New Symmetric Key.
In the dialog, click Generate to generate a new key in JWK format.
Replace the generated value for the k
property with a Base64-encoded key that you just copied. Note that this should be the actual key, not the tampered JWT that you used in the previous section.
Part 4 — Modify and sign the token
Go back to your request in Burp Repeater and change the path to /admin
.
Switch to the extension-generated JSON Web Token tab.
In the header of the JWT, make sure that the alg
parameter is set to HS256
.
In the JWT payload, change the value of the sub
claim to administrator
.
At the bottom of the tab, click Sign, then select the symmetric key that you generated in the previous section.
- Make sure that the Don’t modify header option is selected, then click OK. The modified token is now signed using the server’s public key as the secret key.
- Send the request and observe that you have successfully accessed the admin panel.
- In the response, find the URL for deleting Carlos (
/admin/delete?username=carlos
). Send the request to this endpoint to solve the lab.