Write-up: JWT authentication bypass via jwk header injection @ PortSwigger Academy

Frank Leitner
InfoSec Write-ups
Published in
4 min readSep 22, 2022

--

This write-up for the lab JWT authentication bypass via jwk header injection is part of my walk-through series for PortSwigger’s Web Security Academy.

Learning path: Advanced topics → JWT attacks

Python script: script.py

Lab description

Steps

As usual, the first step is to analyze the functionality of the lab application. In this lab, it is a blog platform. To help with this lab I use the extension JWT Editor (to be found in the BApp Store or as a standalone version on github)

The lab is about authenticated functionality. I use the credentials provided and log in as wiener. Burp identifies the session cookie as JWT and decodes it straight away:

The theory

The server uses RS256 as the algorithm for the token. There are multiple options that I can follow

  1. None algorithm / strip signature
  2. Inject my own key
  3. Obtain the private key (and password if it is protected)

The first option is the easiest to test. In theory, the next step would be to check whether I can remove the signature or change the algorithm to none. However, there are dedicated labs for these two issues so I skip the checks here. Refer to my write-ups for JWT authentication bypass via flawed signature verification and JWT authentication bypass via unverified signature for details.

The second option has two flavors. I can either change the algorithm to HS256 and inject a secret key or I keep the algorithm and inject an RSA key. It is always best to change as little as possible, so trying to inject an RSA key changes only one variable. I also do not know whether the backend uses the algorithm provided in the token or enforces RS256.

Option (3) is unlikely and also the most difficult, so I skip this for now until everything else fails.

I now generate a new RSA key in the JWT Editor key store:

Generation of a new RSA key pair

In the Burp Proxy, I send the request to /my-account to Repeater and select the Attack -> Embedd JWK option. I select the RSA signing key I just generated:

Embedding JWK and signing with it

After clicking OK, the signature is updated automatically. If the request contains an invalid or no JWT as the session cookie, the application redirects to the /login page.

I send the request and the response contains my account page, confirming that the signature verification on the backend used the RSA public key information I injected in the JWT header.

Backend accepts my own signature using injected public key

The malicious payload

I change the sub value of the token to administrator, perform the Attack -> Embedd JWK option again, copy the serialized JWT and update my session cookie in the browser (for manipulating the cookie, I use the Cookie-Editor):

Generating the session cookie for the administrator

Now I refresh the /admin page. Instead of the error Admin interface only available if logged in as an administrator, I am greeted with the user management page:

After clicking on the Delete link for user carlos, the lab updates to

Originally published at https://github.com.

New to Medium? Become a Medium member to access all stories on the platform and support me at no extra cost for you!

From Infosec Writeups: A lot is coming up in the Infosec every day that it’s hard to keep up with. Join our weekly newsletter to get all the latest Infosec trends in the form of 5 articles, 4 Threads, 3 videos, 2 GitHub Repos and tools, and 1 job alert for FREE!

--

--

Tech nerd, doing security stuff for fun and some as a job | CISSP-ISSAP, OSCP