[This lab](https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jwk-header-injection) uses a JWT-based mechanism for handling sessions. The server supports the `jwk` parameter in the JWT header. ### 1. What makes this attack possible? * **Normal flow:** 1. Client sends JWT → server extracts header. 2. Server looks up the **trusted key** (by `kid`) from its key store. 3. It verifies the signature. * **Vulnerable flow (this lab):** 1. Server accepts any `jwk` object embedded *inside* the header. 2. It blindly trusts that key and verifies the signature **with the attacker-supplied key**. 3. If the signature matches the embedded key, the token is treated as valid. > Outcome: the attacker becomes their own Certificate Authority for the application. ### 2. Tool stack | Tool | Reason | | ---------------------------------------- | --------------------------------- | | **Burp Suite** + **JWT Editor** (BApp) | Generate keys, embed JWK, re-sign | | *(Alternative)* `jwt-cli`, `python-jose` | DIY route if you prefer scripts | --- ### 3. TL;DR cheat-sheet 1. Log in as **wiener\:peter** → capture `session=<jwt>`. 2. In **JWT Editor ▸ Keys**: **New RSA Key → Generate** (stores key pair). 3. In **Repeater** change request path to `/admin`. 4. Switch to **JSON Web Token** tab → payload `"sub":"administrator"`. 5. Click **Attack ▸ Embedded JWK** → pick your new RSA key. *Header now contains `jwk` + matching `kid`; token auto-signed with your private key.* 6. Send → **200 OK** admin panel. 7. Request **/admin/delete?username=carlos** → lab solved. --- ### 4. Deep-dive walkthrough #### 4.1 Intercept the original token * Start the lab, log in as **wiener\:peter**. * In **Proxy ▸ HTTP history** locate `GET /my-account`. * Observe cookie: ``` session=eyJhbGciOiJSUzI1NiIsImtpZCI6ImFwcC1rZXkxIn0... ``` #### 4.2 Generate your own RSA key pair 1. **Burp ▸ JWT Editor ▸ Keys ▸ New RSA Key**. 2. Click **Generate** (2048-bit by default) → **OK**. Burp stores: * `kid` – random UUID * `n`, `e` – public modulus/exponent * private key – for signing ![[CleanShot 2025-07-20 at 14.17.48.png]] #### 4.3 Forge the admin token 1. Send the captured request to **Repeater**. 2. Change the path to `/admin`. 3. In **JSON Web Token** tab (provided by extension): * Payload → replace `"sub":"wiener"` with `"administrator"`. 4. Click **Attack ▸ Embedded JWK** → select your RSA key. *Burp does three things automatically:* ![[CleanShot 2025-07-20 at 14.18.22.png]] * Inserts a `jwk` object (public part) into the header. * Updates `kid` to match. * Signs the token with your private key. Header after injection (pretty-printed): ```json { "alg": "RS256", "typ": "JWT", "kid": "e7d1...7f1", "jwk": { "kty": "RSA", "kid": "e7d1...7f1", "n": "0vx7...Yl7w", "e": "AQAB" } } ``` #### 4.4 Exploit * Hit **Send**. * Response **200 OK** shows admin dashboard. * Find link: ```html <a href="/admin/delete?username=carlos">Delete</a> ```