# JWT

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.

A JWT consists of **3 parts**:  `header`<mark style="color:red;">**`.`**</mark>`payload`<mark style="color:red;">**`.`**</mark>`signature`

## Attacks

* The application doesn't verify the signature (but only decode).
* Change `"alg": "none"` in header (bypass filters using classic obfuscation techniques, such as mixed capitalization and unexpected encodings).
* Brute force with wordlist ([W1](https://github.com/wallarm/jwt-secrets/blob/master/jwt.secrets.list), [W2](https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/scraped-JWT-secrets.txt)) using [hashcat](https://ivalexev.gitbook.io/rednote/password-cracking/offline#hashcat).\
  `hashcat -a 0 -m 16500 <jwt> <wordlist>`

### JWT header parameter injections

In `header`:

* Only the `alg` header parameter is mandatory
* `jwk` (JSON Web Key) - Provides an embedded JSON object representing the key.
* `jku` (JSON Web Key Set URL) - Provides a URL from which servers can fetch a set of keys containing the correct key.
* `kid` (Key ID) - Provides an ID that servers can use to identify the correct key in cases where there are multiple keys to choose from. Depending on the format of the key, this may have a matching `kid` parameter.

{% tabs %}
{% tab title="jwk" %}
Injecting self-signed JWTs via the jwk parameter.\
Ideally, servers should only use a limited whitelist of public keys to verify JWT signatures. However, misconfigured servers sometimes use any key that's embedded in the `jwk` parameter.

With  [JWT Editor extension](https://portswigger.net/bappstore/26aaa5ded2f74beea19e2ed8345a93dd):

* Generate a new RSA key in JWT Editor Keys
* Modify the token's payload in Burp Repeter in JSON Web Token tab
* Click Attack, then select **Embedded JWK** and choose your newly generated RSA key.
  {% endtab %}

{% tab title="jku" %}
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.\
A JWK Set is a JSON object containing an array of JWKs representing different keys.

{% code title="Example" overflow="wrap" %}

```json
{
    "keys": [
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
            "n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
        },
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
            "n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
        }
    ]
}
```

{% endcode %}

More secure websites will only fetch keys from trusted domains, but you can sometimes take advantage of URL parsing discrepancies to bypass this kind of filtering.

See [URL Validation Bypass](https://portswigger.net/web-security/ssrf/url-validation-bypass-cheat-sheet) and [Inconsistencies on URL Parser](https://ivalexev.gitbook.io/rednote/pentesting-process/web-attacks/ssrf#inconsistencies-on-url-parser).
{% endtab %}

{% tab title="kid" %}
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.\
In this case, an attacker could potentially point the `kid` parameter to a predictable, static file, then sign the JWT using a secret that matches the contents of this file.

ex. use use `/dev/null` (null key)

<mark style="color:red;">**`!!!`**</mark> If the server stores its verification keys in a database, the `kid` header parameter is also a potential vector for SQL injection attacks.
{% endtab %}
{% endtabs %}

### Algorithm confusion attacks

Generally, the JWT verification method is unique for all types of signatures, both symmetric and asymmetric. This method takes two parameters:

* JWT tokens
* **Secret** (symmetric encryption) or **Public key** (asymmetric encryption)

If developers assume that the JWT is always passed signed with an asymmetric encryption method such as RS256, and always pass the fixed public key to the verification method, a vulnerability may occur.

The attack consists of:

1. Obtain the server's public key
   1. Standard endpoint: `/jwks.json` or `/.well-known/jwks.json`&#x20;
   2. Extract it from a pair of existing JWTs ([jwt\_forgery.py](https://github.com/silentsignal/rsa_sign2n/blob/release/standalone/jwt_forgery.py))\
      &#x20; `docker run --rm -it portswigger/sig2n <token1> <token2>`
2. Convert the public key to a suitable format
   1. With the extension loaded, in Burp's main tab bar, go to the **JWT Editor Keys** tab.
   2. Click **New RSA** Key. In the dialog, paste the JWK that you obtained earlier.
   3. Select the **PEM** radio button and copy the resulting PEM key.
   4. Go to the **Decoder** tab and Base64-encode the PEM.
   5. Go back to the **JWT Editor Keys** tab and click **New Symmetric Key**.
   6. In the dialog, click **Generate** to generate a new key in JWK format.
   7. Replace the generated value for the `k` parameter with a Base64-encoded PEM key that you just copied.
   8. Save the key.
3. Create a malicious JWT with a modified payload and the `alg` header set to `HS256` (symmetric encryption).
4. Sign the token with HS256, using the public key as the secret.

In this way the verification method will be invoked with the token e the public key which however will be considered as secret, this is because the method defined in the header is a symmetric encryption.\
In other words it checks that the jwt token has been signed with the public key.
