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.

You can log in to your own account using the following credentials: wiener:peter

Tip

We recommend familiarizing yourself with how to work with JWTs in Burp Suite before attempting this lab.

We have also provided a simplified version of the jwt_forgery.py tool to help you. For details on how to use this, see Deriving public keys from existing tokens.

Hint

You can assume that the server stores its public key as an X.509 PEM file.

Solution

Part 1 - Obtain two JWTs generated by the server
  1. In Burp, load the JWT Editor extension from the BApp store.

  2. In the lab, log in to your own account and send the post-login GET /my-account request to Burp Repeater.

  3. In Burp Repeater, change the path to /admin and send the request. Observe that the admin panel is only accessible when logged in as the administrator user.

  4. Copy your JWT session cookie and save it somewhere for later.

  5. Log out and log in again.

  6. Copy the new JWT session cookie and save this as well. You now have two valid JWTs generated by the server.

Part 2 - Brute-force the server's public key
  1. 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.

  2. 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.

  3. Copy the tampered JWT from the first X.509 entry (you may only have one).

  4. Go back to your request in Burp Repeater and change the path back to /my-account.

  5. 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
  1. 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.

  2. In Burp, go to the JWT Editor Keys tab and click New Symmetric Key.

  3. In the dialog, click Generate to generate a new key in JWK format.

  4. 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.

  5. Save the key.

Part 4 - Modify and sign the token
  1. Go back to your request in Burp Repeater and change the path to /admin.

  2. Switch to the extension-generated JSON Web Token tab.

  3. In the header of the JWT, make sure that the alg parameter is set to HS256.

  4. In the JWT payload, change the value of the sub claim to administrator.

  5. At the bottom of the tab, click Sign, then select the symmetric key that you generated in the previous section.

  6. 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.

  7. Send the request and observe that you have successfully accessed the admin panel.

  8. In the response, find the URL for deleting carlos (/admin/delete?username=carlos). Send the request to this endpoint to solve the lab.

Community solutions

Intigriti
Emanuele Picariello
Michael Sommer