hacktricks/pentesting-web/hacking-jwt-json-web-tokens.md
2021-03-08 16:08:00 +00:00

10 KiB
Raw Blame History

JWT Vulnerabilities Json Web Tokens

Part of this post was taken from: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Author of the great tool to pentest JWTs https://github.com/ticarpi/jwt_tool

Quick Wins

Run jwt_tool ****with mode All Tests! and wait for green lines

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>"

If you are lucky the tool will find some case where the web application is correctly checking the JWT:

Then, you can search the request in your proxy or dump the used JWT for that request using jwt_ tool:

python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"

Tamper data without modifying anything

You can just tamper with the data leaving the signature as is and check if the server is checking the signature. Try to change your username to "admin" for example.

Is the token checked?

  • If an error message occurs the signature is being checked - read any verbose error info that might leak something sensitive.
  • If the page returned is different the signature is being checked.
  • If the page is the same then the signature is not being checked - time to start tampering the Payload claims to see what you can do!

Origin

Check where the token originated in your proxy's request history. It should be created on the server, not the client.

  • If it was first seen coming from the client-side then the key is accessible to client-side code - seek it out!
  • If it was first seen coming from the server then all is well.

Duration

Check if the token lasts more than 24h... maybe it never expires. If there is a "exp" filed, check if the server is correctly handling it.

Brute-force HMAC secret

#hashcat
hashcat -m 16500 -a 0 jwt.txt .\wordlists\rockyou.txt

#https://github.com/Sjord/jwtcrack
python crackjwt.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoie1widXNlcm5hbWVcIjpcImFkbWluXCIsXCJyb2xlXCI6XCJhZG1pblwifSJ9.8R-KVuXe66y_DXVOVgrEqZEoadjBnpZMNbLGhM8YdAc /usr/share/wordlists/rockyou.txt

#John
john jwt.txt --wordlist=wordlists.txt --format=HMAC-SHA256

#https://github.com/ticarpi/jwt_tool
python3 jwt_tool.py -d wordlists.txt <JWT token>

#https://github.com/brendan-rius/c-jwt-cracker
./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoie1widXNlcm5hbWVcIjpcImFkbWluXCIsXCJyb2xlXCI6XCJhZG1pblwifSJ9.8R-KVuXe66y_DXVOVgrEqZEoadjBnpZMNbLGhM8YdAc 1234567890 8

#https://github.com/mazen160/jwt-pwn
python3 jwt-cracker.py -jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoie1widXNlcm5hbWVcIjpcImFkbWluXCIsXCJyb2xlXCI6XCJhZG1pblwifSJ9.8R-KVuXe66y_DXVOVgrEqZEoadjBnpZMNbLGhM8YdAc -w wordlist.txt

#https://github.com/lmammino/jwt-cracker
jwt-cracker "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" "abcdefghijklmnopqrstuwxyz" 6

Modify the algorithm to None CVE-2015-9235

Set the algorithm used as "None" and remove the signature part.

Use the Burp extension call "JSON Web Token" to try this vulnerability and to change different values inside the JWT send the request to Repeater and in the "JSON Web Token" tab you can modify the values of the token. You can also select to put the value of the "Alg" field to "None".

Change the algorithm RS256(asymmetric) to HS256(symmetric) CVE-2016-5431

The algorithm HS256 uses the secret key to sign and verify each message.
The algorithm RS256 uses the private key to sign the message and uses the public key for authentication.

If you change the algorithm from RS256 to HS256, the back end code uses the public key as the secret key and then uses the HS256 algorithm to verify the signature.

Then, using the public key and changing RS256 to HS256 we could create a valid signature. You can retrieve the certificate of the web server executing this:

openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem

New public key inside the header

An attacker embeds a new key in the header of the token and the server uses this new key to verify the signature CVE-2018-0114.

This can be done with the "JSON Web Tokens" Burp extension.
Send the request to the Repeater, inside the JSON Web Token tab select "CVE-2018-0114" and send the request.

JWKS Spoofing

If the token uses a “jku” Header claim then check out the provided URL. This should point to a URL containing the JWKS file that holds the Public Key for verifying the token. Tamper the token to point the jku value to a web service you can monitor traffic for.

If you get an HTTP interaction you now know that the server is trying to load keys from the URL you are supplying. Use jwt_tool's -S flag alongside the -u http://example.com argument to generate a new key pair, inject your provided URL, generate a JWKS containing the Public Key, and sign the token with the Private Key

Kid issues

kid is an optional header claim which holds a key identifier, particularly useful when you have multiple keys to sign the tokens and you need to look up the right one to verify the signature.

"kid" issues - reveal key:

If the claim "kid" is used in the header, check the web directory for that file or a variation of it. For example if "kid":"key/12345” then look for /key/12345 and /key/12345.pem on the web root.

"kid" issues - path traversal:

If the claim "kid" is used in the header, check if you can use a different file in the file system. Pick a file you might be able to predict the content of, or maybe try "kid":"/dev/tcp/yourIP/yourPort to test connectivity, or even some SSRF payloads...
Use jwt_tool's -T flag to tamper the JWT and change the value of the kid claim, then choose to keep the original signature

python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""

Miscellaneous attacks

The following are known weaknesses that should be tested for.

Cross-service relay attacks

Some web applications use a trusted JWT service to generate and manage tokens for them. In the past some instances have occurred where a token generated for one of the JWT services clients can actually be accepted by another of the JWT services clients.
If you observe the JWT being issued or renewed via a third-party service then it is worth identifying if you can sign up for an account on another of that services clients with your same username/email. If so try taking that token and replaying it in a request to your target. Is it accepted?

  • If your token is accepted then you may have a critical issue allowing you to spoof any users account. HOWEVER, be aware that if you are signing up on a third party application you may need to seek permission for wider testing permissions in case it enters a legal grey-area!

Is exp checked?

The “exp” Payload claim is used to check the expiry of a token. As JWTs are often used in the absence of session information, so they do need to be handled with care - in many cases capturing and replaying someone elses JWT will allow you to masquerade as that user.
One mitigation against JWT replay attacks that is advised by the JWT RFC is to use the “exp” claim to set an expiry time for the token. It is also important to set the relevant checks in place in the application to make sure this value is processed and the token rejected where it is expired. If the token contains an “exp” claim and test time limits permit it - try storing the token and replaying it after the expiry time has passed. Use jwt_tool's -R flag to read the content of the token, which includes timestamp parsing and expiry checking (timestamp in UTC)

  • If the token still validates in the application then this may be a security risk as the token may NEVER expire.

x5u and jku

jku

jku stands for JWK Set URL.
If the token uses a “jkuHeader claim then check out the provided URL. This should point to a URL containing the JWKS file that holds the Public Key for verifying the token. Tamper the token to point the jku value to a web service you can monitor traffic for.

If you get an HTTP interaction you now know that the server is trying to load keys from the URL you are supplying. Use jwt_tool's -S flag alongside the -u http://example.com argument to generate a new key pair, inject your provided URL, generate a JWKS containing the Public Key, and sign the token with the Private Key

x5u

X.509 URL. A URI pointing to a set of X.509 a certificate format standard public certificates encoded in PEM form. The first certificate in the set must be the one used to sign this JWT. The subsequent certificates each sign the previous one, thus completing the certificate chain. X.509 is defined in RFC 52807 . Transport security is required to transfer the certificates.

Try to change this header to an URL under your control and check if any request is received. In that case you could tamper the JWT.

You can also abuse both of these vulns if Open redirects, header injection or if you can upload a file inside the server and the server is just whitelisting the domain and not the path.

JWT Registered claims

{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" caption="" %}

Tools

{% embed url="https://github.com/ticarpi/jwt_tool" caption="" %}