✍️
Writeups and Walkthroughs
HomeGitHubPortfolio Twitter/X Medium Cont@ct
  • ✍️Writeups and Walkthroughs
  • THM
    • Simple CTF
    • RootMe
    • Eternal Blue
    • Vulnversity
    • Pickle Rick
    • Brooklyn Nine Nine
    • Kenobi
    • Bounty Hacker
    • Overpass
    • LazyAdmin
    • Ignite
    • Bolt
    • Agent Sudo
    • Anonymous
    • Startup
    • Wgel
    • Lian_Yu
    • Blog
    • ColdBox
    • H4cked
    • Smag Grotto
    • Ice
    • Blaster
    • The Sticker Shop
    • 🔟OWASP
      • 1️⃣Injection
    • Active Directory Basics
    • Attacktive Directory
    • Post-Exploitation Basics
  • HackTheBox
    • Active
    • Devel
    • Delivery
    • Analytics
    • Bashed
    • Valentine
    • Sau
    • Sunday
    • Cap
    • Bizness
    • Chemistry %
  • Vulnhub
    • Brainpain (BoF)
  • DockerLabs
    • Trust
    • Upload
    • Vacaciones
  • DVWA
    • Install and configure DVWA
    • Command Injection
    • CSRF
    • File Inclusion
    • SQL Injection
    • SQLi Blind
  • Mutillidae II
    • Install & configure OWASP Mutillidae II
    • SQLi
      • SQLi Login Bypass
      • Extracting Data
      • Finding Number of Columns
      • Pivoting with SQL injection
    • Command Injection
      • Extracting User Accounts
      • Web Shell
    • IDOR & File Inclusion
      • Edit Another User's Profile
      • Extracting User Accounts
      • Extracting User Accounts with Local File Inclusion
      • Web Shell with Remote File Inclusion (RFI)
    • XSS
      • XSS Reflected
      • XSS Stored
      • XSS DOM-Based
  • Secure Bank
    • Install & configure Secure Bank
    • -----
      • SQLi Login Bypass
      • Extracting Data
      • Finding Number of Columns
      • Pivoting with SQL injection
    • -----
      • Extracting User Accounts
      • Web Shell
  • PortSwigger - Web Security Academy
    • Burp Suite Config
    • Information Disclosure
      • Information disclosure vulnerabilities
      • Common sources of information disclosure
        • Information disclosure in error messages
        • Information disclosure on debug page
        • Source code disclosure via backup files
        • Authentication bypass via information disclosure
        • Information disclosure in version control history
    • Essential skills
      • Obfuscating attacks using encodings
        • SQL injection with filter bypass via XML encoding
      • Using Burp Scanner
      • Identifying unknown vulnerabilities
    • Server-side vulnerabilities
      • Path traversal
        • File path traversal, simple case
      • Access control
        • Unprotected admin functionality
        • Unprotected admin functionality with unpredictable URL
        • User role controlled by request parameter
        • User ID controlled by request parameter, with unpredictable user IDs
        • User ID controlled by request parameter with password disclosure
      • Authentication
        • Username enumeration via different responses
        • 2FA simple bypass
      • Server-side request forgery (SSRF)
        • Basic SSRF against the local server
        • Basic SSRF against another back-end system
      • File upload vulnerabilities
        • Remote code execution via web shell upload
        • Web shell upload via Content-Type restriction bypass
      • OS Command Injection
        • OS command injection, simple case
      • SQL injection
        • SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
        • SQL injection vulnerability allowing login bypass
    • JWT Attacks
      • Json Web Tokens (JWT)
      • Exploiting JWT
        • JWT authentication bypass via unverified signature
        • JWT authentication bypass via flawed signature verification
        • JWT authentication bypass via weak signing key
        • To-Do
          • JWT authentication bypass via jwk header injection - %
          • JWT authentication bypass via jku header injection - %
          • JWT authentication bypass via kid header path traversal - %
    • API Testing
      • API Testing
        • Exploiting an API endpoint using documentation
        • Finding and exploiting an unused API endpoint
        • Exploiting a mass assignment vulnerability
      • Server-side parameter pollution
        • Exploiting server-side parameter pollution in a query string
    • Deserialization Insecure
      • Serialization vs Deserialization
        • Lab
        • Lab
      • Java Insecure Deserialization
        • Lab
        • Lab
      • PHP Insecure Deserialization
        • Lab
        • Lab
  • HomeMade Labs
    • Active Directory
      • AD Lab Setup
      • AD Enumeration
      • SMB Common Attacks
    • Pivoting
      • Pivoting Theory
      • Pivoting Guidelines
      • Lab (3 Targets)
    • Buffer Overflow (BoF)
      • BoF Theory
      • Brainpain (BoF Lab)
Powered by GitBook
On this page
  • JWT Attacks
  • Working with JWTs in Burp Suite
  • Editing JWTs
  • Adding a JWT signing key
  • Exploiting flawed JWT signature verification
  • Accepting tokens with no signature
  • Brute-forcing secret keys
  • JWT header parameter injections
  • JWT algorithm confusion
  • How to prevent JWT attacks
  • Labs 🔬
  1. PortSwigger - Web Security Academy
  2. JWT Attacks

Exploiting JWT

PreviousJson Web Tokens (JWT)NextJWT authentication bypass via unverified signature

Last updated 1 month ago

JWT Attacks

JWT attacks involve a user sending modified JWTs to the server in order to achieve a malicious goal, usually bypassing authentication and access controls by impersonating another user already authenticated.

The impact of these attacks is really serious, because the attacker who creates valid tokens with arbitrary values ​​can escalate their privileges or impersonate other users, taking complete control of their accounts.

The specifications of JWT are relatively flexible by design, allowing web dev to decide many implementation details, that should introduce vulnerabilities.

These implementation flaws usually mean that the signature of the JWT is not properly verified. This allows an attacker to tamper with the values ​​passed to the application via the token payload. Even if the signature is robustly verified, whether it can truly be trusted depends largely on whether the server's secret key is kept secret. If this key is somehow leaked, or can be guessed or brute-forced, an attacker can generate a valid signature for any arbitrary token, compromising the entire mechanism.

Working with JWTs in Burp Suite

Using Burp Inspector to view and decode JWTs, we can use the JWT Editor extension () to:

  1. Generate cryptographic signing keys.

  2. Edit the JWT.

  3. Resign the token with a valid signature that corresponds to the edited JWT.

Through this extension, the requests with a JWT are automatically flagged, and is possible to view the JWT content in the dedicated section (where the content is automatically decoded in the Inspector panel, commonly in the right box).

Reviewing the encoded content of JWT, we can discover important info and understand the potential modifications to make.

Editing JWTs

To edit a JWT using the JWT Editor extension:

  1. Right-click the request with the JWT and select Send to Repeater.

  2. In the request panel, go to the JSON Web Token tab.

  3. Edit the JSON data as required in the Header and Payload fields.

  4. Click Sign. A new dialog opens.

  5. In the dialog, select the appropriate signing key, then click OK. The JWT is re-signed to correspond with the new values in the header and payload. If you haven't added a signing key, follow the instructions below.

Adding a JWT signing key

  1. Go to the JWT Editor Keys tab.

  2. Click the button for the type of key that you want to add. For example, New Symmetric Key. A new dialog opens.

  3. In the dialog, add the new key:

    • Click Generate to create a new key.

    • Alternatively, paste an existing key into the dialog.

  4. Edit the key as required.

  5. Click OK to save the key.

To add a signing key to Burp using the JWT Editor extension:

Exploiting flawed JWT signature verification

By design, servers don't usually store any information about the JWTs that they issue. Instead, each token is an entirely self-contained entity. This has several advantages, but also introduces a fundamental problem - the server doesn't actually know anything about the original contents of the token, or even what the original signature was. So, if the server doesn't verif the signature properly, there's a nothing to stop an attacker from making arbitrary changes to the rest of the token.

In a scenerio there a JWT contains the following claims:

{
    "username": "carlos",
    "isAdmin": false
}

if the server identifies the session based on this username, modifying its value an attacker can impersonate other logged-in users, same situationr egarding isAdmin value is used for access control, this could provide a simple vector privilege escalation.

Accepting arbitrary signatures

JWT libraries typically provide one method for verifying tokens and another that just decodes them. For example, the Node.js library jsonwebtoken has verify() and decode().

Occasionally, developers confuse these two methods and only pass incoming tokens to the decode() method. This effectively means that the application doesn't verify the signature at all.

Accepting tokens with no signature

Among other things, the JWT header contains an alg parameter. This tells the server which algorithm was used to sign the token and, therefore, which algorithm it needs to use when verifying the signature.

{ "alg": "HS256", "typ": "JWT" }

This is inherently flawed because the server has no option but to implicitly trust user-controllable input from the token which, at this point, hasn't been verified at all.

JWTs can be signed using a range of different algorithms, but can also be left unsigned. In this case, the alg parameter is set to none, which indicates a so-called "unsecured JWT".

Due to the obvious dangers of this, servers usually reject tokens with no signature.

Brute-forcing secret keys

Some signing algorithms, such as HS256 (HMAC + SHA-256), use an arbitrary, standalone string as the secret key. Just like a password, it's crucial that this secret can't be easily guessed or brute-forced by an attacker.

Using brute force tools such as: JohnTheRipper and Hashcat with a good wordlist we've good chances to guess the secret keys.

hashcat -a 0 -m 16500 <jwt> <wordlist>

JWT header parameter injections

According to the JWS specification, only the alg header parameter is mandatory. In practice, however, JWT headers (also known as JOSE headers) often contain several other parameters. The following ones are of particular interest to attackers.

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

Injecting self-signed JWTs via the jwk parameter

The JSON Web Signature (JWS) specification describes an optional jwk header parameter, which servers can use to embed their public key directly within the token itself in JWK format (it rapresents keys as a JSON object). Here below an example of JWT Header:

{
    "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
    "typ": "JWT",
    "alg": "RS256",
    "jwk": {
        "kty": "RSA",
        "e": "AQAB",
        "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
        "n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
    }
}

Misconfigured servers sometimes use any key that's embedded in the jwk parameter.

You can exploit this behavior by signing a modified JWT using your own RSA private key, then embedding the matching public key in the jwk header.

You can also perform this attack manually by adding the jwk header yourself. However, you may also need to update the JWT's kid header parameter to match the kid of the embedded key.

  1. With the extension loaded, in Burp's main tab bar, go to the JWT Editor Keys tab.

  2. Send a request containing a JWT to Burp Repeater.

  3. Click Attack, then select Embedded JWK. When prompted, select your newly generated RSA key.

  4. Send the request to test how the server responds.

Injecting self-signed JWTs via the jku parameter

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. You can see an example of this below.

{
    "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"
        }
    ]
}

JWK Sets like this are sometimes exposed publicly via a standard endpoint, such as /.well-known/jwks.json.

Injecting self-signed JWTs via the kid parameter

Servers may use several cryptographic keys for signing different kinds of data, not just JWTs. For this reason, the header of a JWT may contain a kid (Key ID) parameter, which helps the server identify which key to use when verifying the signature.

Verification keys are often stored as a JWK Set.

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.

{
    "kid": "../../path/to/file",
    "typ": "JWT",
    "alg": "HS256",
    "k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc"
}

You could theoretically do this with any file, but one of the simplest methods is to use /dev/null, which is present on most Linux systems. As this is an empty file, reading it returns an empty string. Therefore, signing the token with a empty string will result in a valid signature.

Note: If you're using the JWT Editor extension, note that this doesn't let you sign tokens using an empty string. However, due to a bug in the extension, you can get around this by using a Base64-encoded null byte. If the server stores its verification keys in a database, the kid header parameter is also a potential vector for SQL injection attacks.

Other interesting JWT header parameters

  • cty (Content Type) - Sometimes used to declare a media type for the content in the JWT payload.

  • x5c (X.509 Certificate Chain) - Sometimes used to pass the X.509 public key certificate or certificate chain of the key used to digitally sign the JWT.

JWT algorithm confusion

Even if a server uses robust secrets that you are unable to brute-force, you may still be able to forge valid JWTs by signing the token using an algorithm that the developers haven't anticipated. This is known as an algorithm confusion attack.

How to prevent JWT attacks

You can protect your own websites against many of the attacks we've covered by taking the following high-level measures:

  • Use an up-to-date library for handling JWTs and make sure your developers fully understand how it works, along with any security implications.

  • Make sure that you perform robust signature verification on any JWTs that you receive, and account for edge-cases such as JWTs signed using unexpected algorithms.

  • Enforce a strict whitelist of permitted hosts for the jku header.

  • Make sure that you're not vulnerable to path traversal or SQL injection via the kid header parameter.

Additional best practice for JWT handling

  • Always set an expiration date for any tokens that you issue.

  • Avoid sending tokens in URL parameters where possible.

  • Include the aud (audience) claim (or similar) to specify the intended recipient of the token. This prevents it from being used on different websites.

  • Enable the issuing server to revoke tokens (on logout, for example).

Although not strictly necessary to avoid introducing vulnerabilities, we recommend adhering to the following best practice when using JWTs in your applications:

Labs 🔬

  • JWT authentication bypass via jwk header injection

  • JWT authentication bypass via jku header injection

  • JWT authentication bypass via kid header path traversal

In the message editor, switch to the extension-generated JSON Web Token tab and the token's payload however you like.

This is especially dangerous if the server also supports JWTs signed using a . 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.

Generate a new RSA key.
modify
symmetric algorithm
JWT authentication bypass via unverified signature
JWT authentication bypass via flawed signature verification
JWT authentication bypass via weak signing key
https://portswigger.net/bappstore/26aaa5ded2f74beea19e2ed8345a93dd