Home JWT Vulnerabilities
Post
Cancel

JWT Vulnerabilities

JWT

JWT Attacks

JWT or JSON Web Tokens is a standard way to send information in JSON format within the HTTP requests. Data is crypotgraphically signed and it is normally used for session handling, authentication, access control mechanisms, etc. The information sent through a JWT is als called “claims”

JWTs consist of three parts, separated by a dot. The header and the payload is Base64 encoded:

  1. Header: Contains information about how the JWT is encoded, such as the type of token (JWT) and the signing algorithm being used.
  2. Payload: Contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims.
    • Registered claims: These are predefined claims, such as “iss” (issuer), “exp” (expiration time), and “sub” (subject).
    • Public claims: These are custom claims defined by those using JWTs, and they are typically not registered in the official IANA JSON Web Token Claims registry.
    • Private claims: These are custom claims that are agreed upon between parties using JWTs.
  3. Signature: To create the signature part, you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that with the secret.

Since the signature depends on the content of the token, a single modification will cause a different signature, so the server (that knows the secret) can validate that the token hasn’t been tampered.

If these tokens are not correctly handled by the server, it is possible to abuse them and bypass authentication and authorization restrictions.

Common Vulnerabilities

Even though JWT are signed, if the server doesn’t validate the signature there is no security at all. You could modify any value and the backend server will take it as valid, even though the signature doesn’t match.

Another common vulnerability is that the “alg” parameter in the header contains the algorithm used to sign the token. If this is set to “none” and the server accept it, it will ignore the signature, so you can modify the content and not worry about the signature at all.

With the normal token we get an Unauthorized:

Untitled

If we modify the token, change the “sub” to administrator, the “alg” to none and delete the signature…

Untitled

We get a OK response

Untitled

If the developers have used weak secrets, the JWT can be brute forced too. If you find the secret, since you know the algorithm because it is specified in the header, you could modify the JWT, sign it again and send the whole JWT with the new signature to the server.

Self Signing JWT

JWT headers can contain some optional parameters:

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

This parameters can be abused to self-sign the modified JWT and the server will accept them since the signature is valid.

  • jwk directly provides an embedded JSON with a public key. If the server doesn’t have a list of valid public keys, you could create your own public and private RSA keys, sign the JWT with the private key and embed the public key in this parameter.
1
2
3
4
5
6
"jwk": {
        "kty": "RSA",
        "e": "AQAB",
        "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
        "n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
    }
  • jku is like jwk but instead of embedding the key, contains a URL pointing to a JSON with valid public keys. If the server fetch keys for untrusted domains, you could publish your own set of public keys and abuse the same vulnerability. You can do this using the JWT Editor Extension in Burp.
    • You first need to create a RSA key, then you can right click and copy the public key :

    Untitled

    • You can paste your public key in your public server:

    Untitled

    • Then you can create your modified jwt and include the jku key in the header, with the url of your public server that contains the public key. You must sign this key with the private key and use it:

    Untitled

  • kid parameter is used to identify a key, it can be a parameter to point to a particular entry in a database, or even a name file. If this parameter is vulnerable to a path traversal attack, an attacker could set this value to a well-kown file with a predictable value and then sign the JWT using a secret that matches the contents of this file.

Untitled

This post is licensed under CC BY 4.0 by the author.