🕸️
Web Security Notes
  • README
  • Portswigger
    • Access Control
      • notes
      • labs
    • Authentication
      • notes
      • labs
    • Business Logic Vulnerabilities
      • notes
      • labs
    • Clickjacking
      • notes
      • labs
    • Command Injection
      • notes
      • labs
    • CORS
      • notes
      • labs
    • CSRF
      • notes
      • labs
    • Directory Traversal
      • notes
      • labs
    • DOM-based Vulnerabilities
      • notes
      • labs
    • File upload Vulnerabilities
      • notes
      • labs
    • HTTP Host Header Attacks
      • notes
      • labs
    • HTTP Request Smuggling
      • notes
      • labs
    • Information Disclosure
      • notes
      • labs
    • Insecure Deserialization
      • notes
      • labs
    • JWT Attacks
      • notes
      • labs
    • OAuth Authentication
      • notes
      • labs
    • Server Side Template Injection
      • notes
      • labs
    • SQL injection
      • notes
      • labs
      • cheat sheet
    • SSRF
      • notes
      • labs
    • Web Cache Poisoning
      • notes
      • labs
    • WebSockets
      • notes
      • labs
    • XSS
      • notes
      • labs
    • XXE Injection
      • notes
      • labs
Powered by GitBook
On this page
  • What are JWTs?
  • JWT attacks
  • JWT algorithm confusion
  1. Portswigger
  2. JWT Attacks

notes

What are JWTs?

  • JSON web tokens (JWTs) - standarized format for sending cryptographically signed JSON data between systems

  • 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

JWT format

  • 3 parts: header, payload and signature separated by dot

  • header and payload parts of a JWT are just base64url-encoded JSON objects

  • header contains metadata about the token itself, while the payload contains actual claims about the user

    eg -

eyJraWQiOiI5MTM2ZGRiMy1jYjBhLTRhMTktYTA3ZS1lYWRmNWE0NGM4YjUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTY0ODAzNzE2NCwibmFtZSI6IkNhcmxvcyBNb250b3lhIiwic3ViIjoiY2FybG9zIiwicm9sZSI6ImJsb2dfYXV0aG9yIiwiZW1haWwiOiJjYXJsb3NAY2FybG9zLW1vbnRveWEubmV0IiwiaWF0IjoxNTE2MjM5MDIyfQ.SYZBPIBg2CRjXAJ8vCER0LA_ENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q7_9qGhQZvy9ZdxEJbwTxRs_6Lb-fZTDpW6lKYNdMyjw45_alSCZ1fypsMWz_2mTpQzil0lOtps5Ei_z7mM7M8gCwe_AGpI53JxduQOaB5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xeLwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA
  • header part is decoded as follow

{ "kid": "9136ddb3-cb0a-4a19-a07e-eadf5a44c8b5", "alg": "RS256" }
  • payload part

{
  "iss": "portswigger",
  "exp": 1648037164,
  "name": "Carlos Montoya",
  "sub": "carlos",
  "role": "blog_author",
  "email": "carlos@carlos-montoya.net",
  "iat": 1516239022
}
  • security of any JWT-based mechanism is heavily reliant on the cryptographic signature

JWT attacks

  • user sending modified JWTs to the server in order to achieve a malicious goal

  • goal is to bypass authentication and access controls by impersonating another user who has been authenticated

  • impact - severe

Exploiting flawed JWT signature verification

  • by design, servers don't store any information about the JWTs that they issue and instead each token is an entirely self-contained entity

  • one problem is that server doesn't know anything about the original contents of the token or even what the original signature was

  • if the server doesn't verify the signature properly, the attacker can chage the rest of the token

  1. Accepting arbitary signatures

  • the application doesn't verify the signature part at all

  • just change the payload parameters and it works

  1. Accepting tokens with no signature

  • in header part, it looks like :

{
  "alg": "HS256",
  "typ": "JWT"
}
  • "alg" parameter is set to none -> unsecured JWT

  • servers usually reject tokens with no signature

  • but this kind of filtering relies on string parsing, and can bypass by using classic obfuscation techniques such as mixed capitalization and unexpected encodings

  1. Brute-forcing secret keys

  • some signing algorithms such as HS256 (HMAC + SHA-256) use an arbitary standalone string as the secret key like password and this secret can't be easily guessed or brute-forced by an attacker

  • otherwise, they may be able to create JWTs with any header and payload values and use that key to resign the token with a valid signature

  • sometimes, develpers make mistakes like forgetting to change default or placeholder secrets, or copy and paste code snippets they find online

  • use hashcat to burte-force

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

JWT header parameter injections

  • only alg header is mandatory

  • but JWT header (JOSE header) often contain several other parameters

  • eg - jwk (JSON Web Key) - provides an embedded JSON object representing the key

    • jku (JSON Web Key Set URL) - provides 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

Injecting self-signed JWTs via jwk

  • JWK - standarized format for representing keys as a JSON object eg -

{
  "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
  "typ": "JWT",
  "alg": "RS256",
  "jwk": {
    "kty": "RSA",
    "e": "AQAB",
    "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
    "n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
  }
}
  • ideally, servers should only use a limited whitelist of public keys to verify JWT signature

  • but, misconfigured servers sometimes use any key that's embedded in the jwk parameter

  • exploit by signing a modified JWT using your own RSA pirvate key, then embedding the matching public key in the jwk header

Injecting self-signed JWTs via jku parameter

  • instead of 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

  • JWK Set - JSON object containing an array of JWKs representing different keys

{
  "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 are sometimes exposed publicly via a standard endpoint /.well-known/jwks.json

  • more secure websites will only fetch keys from trusted domains, and can bypass like SSRF bypass

Injecting self-signed JWTs via the kid parameter

  • header of JWT may contain a kid (Key ID) parameter, which helps the server to identify which key to use when verifying the signature

  • Verification keys are often stored as a JWK Set

  • the server may simply look for the JWK with the same kid as the token

  • kid was not defined a concrete structure

  • developers 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 can potentially force the server to use an arbitary file from its filesystem

{
  "kid": "../../path/to/file",
  "typ": "JWT",
  "alg": "HS256",
  "k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc"
}
  • if the server supports JWTs signed using symmetric algorithm, it is dangerous

  • one simplest methods is in Linux server use /dev/null path, which is an empty file and fetching it return null and signing the token with a Base64-encoded null byte will result a valid signature

Other JWT header parameters

  • cty (Content Type) - to declare a media type for the content in the JWT payload; if you found a way to bypass signature verification, you can try injecting a cty header to change the content type to text/xml or application/x-java-serialized-object which can enable new vectors for XXE and deserialization attacks

  • x5c (X.509 Certificate Chain) - can be used to inject self-signed certificates similar to the jwk header injection (CVE-2017-2800, CVE-2018-2633)

JWT algorithm confusion

  • known as key confusion attacks

  • occur when an attacker is able to force the server to verify the signature of a JSON web token using a different algorithm than is intended by the developers

Symmetric Vs Asymmetric

  • JWT can be signed using different algorithms

  • eg - HS256 (HMAC + SHA256) use a symmetric key means the server uses a single key to both sign and verify the token

![[Pasted image 20221101205841.jpg]]

  • other algorithms such as RS256 (RSA + SHA256) uses asymmetric key pairs which contains a private key which the server uses to sign the token and a mathematically related public key that can be used to verify the signature

![[Pasted image 20221101210036.jpg]]

Performing algorithm confusion attack

  1. Obtain the server's public key

  2. Convert the public key to a suitable format

  3. Create a malicious JWT with a modified payload and the alg header set to HS256

  4. Sign the token with HS256, using the public key as the secret

Step 1. Obtain the server's public key

  • servers sometimes expose their public keys as JSON Web Key (JWK) objects via endpoint such as /jwks.json or /.well-known/jwks.json and they may be stored in an array of JWKs called keys and known as JWK Set

{
	"keys": [
		{
			"kty": "RSA",
			"e": "AQAB",
			"kid": "...",
			"n": "..."
		},
		{
			"kty": "RSA",
			"e": "AQAB",
			"kid": "...",
			"n": "..."
		}
	]
}

Step 2 - Convert the public key to a suitable format

  • version of the key that you use to sign the JWT must be identical to the server's local copy and every signle byte must match including any non-printing characters

  • In Burp

    1. In JWT Editor Keys tab, New RSA > paste the JWK that was obtained earlier

    2. Select the PEM radio button and copy the resulting PEM key

    3. in Decoder Tab, Base64-encode the PEM

    4. in JWT Editor Keys, New Symmetric Key > Generate

    5. replace the generated value for the k parameter with a Base64-encoded PEM key that was copied and save the key

Step 3 - Modify your JWT

  • modify the JWT as you like and make sure the alg header to HS256

Step 4 - Sign the JWT using the public key

  • Sign the token using the HS256 algorithm with the RSA public key as secret

PreviousJWT AttacksNextlabs

Last updated 2 years ago

an attacker can brute-force a server's secret using

wordlist of well-known secrets