Awesome
JWT FuzzHelper for Burp
Purpose
JSON Web Token (JWT) support for Burp Intruder. This extension adds a payload processor for fuzzing JWT claims.
Comparison
JOSEPH and JSON Web Tokens are two extensions that automate some common attacks and provide various views for JWTs. This extension complements those by providing an Intruder hook for more targeted fuzzing and on-the-fly manipulation of JWTs.
Use Cases
Example use cases may include:
- Inserting atypical values for common claims
- Inserting a new claim that may be processed by the application before signature validation (e.g. CVE-2018-0114)
- Easily iterating over a large set of payload claim values if, for example, one has obtained a signing key
- Inserting bogus or unusually encoded strings or bad inputs. For example, those in the Big List of Naughty Strings
- Manipulation of timestamps or expirations in
iat
,exp
, etc... - Fuzzing site specific implementations of
kid
. - Testing for denial of service conditions.
- Classic attacks like testing for
none
type signatures, algorithmic substitution, etc...
This extension will also process JWT tokens that do not have JSON encoded payloads, which, while uncommon, is something other extensions have may have overlooked.
Dependencies
This extension requires you to have Jython installed.
The HS* class of signature algorithms (ie. HS256, HS384, and HS512) are implemented using native Python libraries. The RS*, ES*, PS*, and None class of signatures are generated via the pyjwt and rsa libraries. Since pyjwt relies on Python cryptography
libs and these libs cannot be installed via Jython, you will need to specify a folder for loading additional Python modules in Extender -> Options -> Python Environment. If you are not planning on making use of ES*, RS*, or PS* algorithms, you do not need pyjwt
or rsa
. You can find the location of your libraries with the command python -c "import sys; print sys.path;"
.
Installation
Install Python dependencies
$ pip install -r requirements.txt
Install the extension.
You can do this in the extender pane.
Extender -> Extensions -> Add -> Type: Python -> Load burp-jwt-fuzzhelper.py
Add your external modules path
The pyjwt
libs rely on C extensions that cannot be installed via Jython. Users need to specify an external path for loading modules.
After finding your environment import paths with python -c "import sys; print sys.path;"
, locate pyjwt. On Kali this is usually in
some folder named dist-packages
, on Macs in site-packages
. You can confirm by grepping for the module (e.g. ls /usr/lib/python2.7/dist-packages/ | grep -i pyjwt
.
Refer to this issue if you are having problems.
Usage
Important
- You must disable payload encoding for the
.
character in Intruder options, or the JWT delimiters will be URL encoded.
Calling the extension
You can invoke the extension in the Intruder tab via payload processor pane
<img src="https://github.com/pinnace/burp-jwt-extension-images/blob/master/payload_processing.png" width="65%" height="65%"> <img src="https://github.com/pinnace/burp-jwt-extension-images/blob/master/payload_processing_rule.png" width="65%" height="65%"> <img src="https://github.com/pinnace/burp-jwt-extension-images/blob/master/processing_rule.png" width="65%" height="65%"> <img src="https://github.com/pinnace/burp-jwt-extension-images/blob/master/invoke_processor.png" width="65%" height="65%">Configuration
This fuzzer uses jq's Object Identifier-Index or a regular expression to select fields for fuzzing.
Options
Target Selection
: Select either the Header or the Payload portion of a JWT to fuzzJSON Selector
: Specify a filter using jq's Object Identifier-Index (e.g..user.role
) or a regex depending on whetherUse regex as JSON selector
is checked.
- For Object Identifier-Index selectors, a single
.
is an empty selector. If the selector is not empty and this claim does not exist, it will be created. - For regular expressions, the regex is passed to
re.sub
. An empty selector is no character.
Use regex as JSON selector
: As stated, optionally use a regex.Generate Signature
: Whether or not to generate a signatureSignature Algorithm
: IfGenerate Signature
is True, then use this algorithmSigning Key
: Optional signing key to paste. If using RS, ES, or PS family of algorithms, this key must be a valid signing key.Signing Key From File
: Optionally load key from file. If selected, optionPath to Signing Key
will appear. Useful if key is raw bytes and generally more reliable. Recommended.Signing Key From Command
: Optionally obtain key from external comand. If selected, optionPath to Signing Cmd
will appear. Useful if signing process is not standard or not supported. The command should expect onlyencoded(header).encoded(payload)
string as an argument and print base64-encoded key to standard output.Path to Signing Key
: Path to file with the signing key. If using RS, ES, or PS family of algorithms, this key must be a valid signing key.
Selector Example: Selecting alg
If you wanted to fuzz the alg
field, you would use "Header" for your target selection and .alg
as your selector
Selector Example: Selecting a nested claim
Given the claim:
"user" : {
"username" : "john.doe",
"role" : "admin"
}
Say you want to fuzz role. You would use .user.role
as your selector. If you were using a regex, you might just use admin
.
Fuzzing examples
Example 1: Fuzzing for None
Say you want to test if an application can be tricked into accepting none
as a valid hashing algorithm. This vulnerability was originally discussed here. You may want to try various permutations of none (e.g. NoNe
, nOne
, noNe
, etc). Note that this is not the same as selecting 'None' as the Signature Algorithm, which will simply use pyjwt
.
- Use
.alg
as your selector - Strip signature from your token
- Add your payload list to Intruder
- Run Intruder. One can see the JSON Web Tokens extension is also handy here
Example 2: Algorithmic substitution
Say you want to test if an application can be tricked into using a public key as an HMAC key.
- Use an empty selector
.
, or try fuzzing another claim (e.g. Payload ->.user.name
) to see if your attack has been successful. - Set
Generate Signature
to True - Select
HS256
as your signature algorithm - Specify the path to the public key, or paste the key in the text box (be careful with
\n
s)
Example 3: kid
claim fuzzing
Bitcoin CTF had a challenge last year involving an improperly handled kid
field. Here's how this extension could help you attack that.
Looking at RFC7515, we can see that the kid
(key id) value is an optional claim field in the header section of a JWT token providing a 'hint' to the operator as to which key was used to sign the token. This is useful if multiple keys are used. Implementation itself is unspecified and up to the operator. Since the kid
parameter is parsed before verifying the signature and implementation is up to the operator, this field presents a promising attack vector.
In the Bitcoin CTF, the kid
field turned out to be a filename under control of the user. By specifying a CSS or JS file with known contents and manipulating the algorithm, one could generate a valid token. To test this with this fuzzer, one could do the following:
To exploit this using the fuzzer you would do the following:
- Select the Header as your target and
.kid
as your selector - Set Generate Signature? to "True"
- Select the signature algorithm, in this case HS256
- Dump the known file contents into the Signing Key text field
- Hit save
Or
<img src="https://github.com/pinnace/burp-jwt-extension-images/blob/master/kid_config2.png" width="75%" height="75%">- Add your fuzz list
- Run Intruder
- Victory dance
Issues or feature requests
PRs welcome. Please open an issue if you have encountered a bug or want to see additional features added. Currently, the fuzzer only supports fuzzing a single claim at a time. If there is interest in supporting functions like Pitchfork intruder positions, I may consider adding. I am also exploring adding an IScannerInsertionPoint for the active scanner.
This extension has been submitted to Portswigger for inclusion in the BApp store pending review.