Fuzzie
Fuzzie is a simple grey-box fuzz testing tool available as VSCode extension for fuzz testing REST API and GraphQL.
The ability to fuzz test right in VSCode brings about several benefits:
- As early as while debugging APIs in VSCode running on localhost, you can concurrently use Fuzzie to fuzz test your APIs.
As Fuzzie also sends random unpredictable data, you can catch common bugs like unhandled input parameters early in development.
- fuzz tests guided by an intuitive WebView
- Being available in VSCode allows developers to conveniently fuzz test anytime without prior knowledge of fuzzing
*Things to Note
- Depending on wordlist type, Fuzzie can send malicious strings from SecList, recommend to use Fuzzie in test environments only
- requires Python 3.10 and above
- Fuzzie uses port 50001
fuzzer engine listens on http://localhost:50001 serving requests from webview
- Fuzzie uses sqlite internally to store all data, when upgrading to a newer extension version, previous data will not be retained
- On the very first launch, Fuzzie can take up to 10 - 12 secs to start up due to data loading
Content
Launching Fuzzie
Open VSCode command palette (Ctrl + Shift + P) and search for "Fuzzie"
Using Fuzzie
Fuzzie VSCode extension provides a webview for you to perform everything from API and GraphQL discovery to fuzzing and analyzing test result, all in a single place.
1. Webview Navigation
2. Start by creating a new API Fuzz Context
A Fuzz Context contains a list of cohesive "test cases" created by writing HTTP Request Messages.
Each test case contains HTTP verb, domain name, port, path, querystring, headers and body and Fuzzie make HTTP requests against all test cases in a Fuzz Context.
2. Write HTTP Request Messages
Your REST and GraphQL target endpoints are described by writing Request Messages.
The concept of Request Message is fully inspired by Hau Chao's VSCode Rest Client project.
{VERB} {url + optional port number}
{headers}
{body}
In request message, you can replace any part of path, querystring, header, body with Fuzzie's built-in Wordlists.
By replacing parameter with wordlist {{ wordlist type }}, during fuzzing, Fuzzie will replace the wordlist with fuzz data depending on the type of wordlist.
for example:
GET https://httpbin.org/get
?name={{username}}
&address={{string}}
&order=5
&mode={{string}}
Content-Type: application/xml
Authorization: {{ string }}
CustomHeader-1: {{ digit }}
CustomHeader-2: {{ filename }}
CustomHeader-3: {{ username }}
Wordlist Types
The following are built-in wordlist-types, more will be added in future
Type = wordlist provides data
Type = function acts on your provided custom data
| WordList Type | Is Primitive wordlist type | file upload | Description | Type |
| ------------- |-------------| -------------| ------------- | ------------- |
| {{ string }} | yes | no | naughty strings from minimaxir/big-list-of-naughty-strings | wordlist |
| {{ xss }} | yes | no | cross-site scripting strings from danielmiessle/seclist | wordlist |
| {{ sqlinject }} | yes | no | sql-injection strings from danielmiessle/seclist | wordlist |
| {{ bool }} | yes | no | boolean values and something naughty | wordlist |
| {{ digit }} | yes | no | Integers, floats and something naughty | wordlist |
| {{ char }} | yes | no | naughty chars | wordlist |
| {{ image }} | no | yes | DALL-E images and a mix of naughty payloads (same as {{ file }} ) from danielmiessle/seclist | wordlist |
| {{ pdf }} | no | yes | Fuzzie generated fake PDF with a mix of naughty payloads (same as {{ file }} ) from danielmiessle/seclist | wordlist |
| {{ file }} | no | yes | naught payload from danielmiessle/seclist |
|
{{
'
custom file content
'
| myfile('filename.csv')
}} | no | yes | Custom file content within single quite '...' are uploaded as file
{{
'
this is a file content
{{string}} {{username}}
'
| myfile("data.json")
}} | wordlist |
| {{ datetime }} | yes | no | date + time | wordlist |
| {{ date }} | yes | no | date only | wordlist |
| {{ time }} | yes | no | time only | wordlist |
| {{ username }} | yes | no | hacked usernames from danielmiessler seclist | wordlist |
| {{ password }} | yes | no | hacked password from danielmiessler seclist | wordlist |
| {{ filename }} | yes | no | random file name and extensions | wordlist |
| {{ httppath }} | yes | no | discover directories and files | wordlist |
| {{ numrange(start, end) }} | yes | no | increment number by 1 from start to end.
Example numrange(1, 5000): result is 1, 2, 3,...4999, 5000 | function |
| {{ 'a quick brown fox' | mutate }} | yes | no | input will be mutated | function |
| {{ ['a', 'list', 'of', 'items' ] | random }} | yes | no | returns a random item from your list | function |
| {{
'single string to be base64 encoded' | base64e }}
{{ ['list', 'of', 'items', 'to be base64 encoded'] | base64e }}
| yes | no | base64 encodes your input, or if a list is supplied, randomly pick an item and encodes it | function |
| {{
'base64 encoded string to be decoded' | base64d }}
{{ ['list', 'of', 'encoded', 'items', 'to be base64 decoded'] | base64d }}
| yes | no | base64 encodes your input, or if a list is supplied, randomly pick an item and encodes it | function |
2.1 Request Message Examples
Request message syntax follows VSCode Rest Client closely.
"Samples" drop-down button allows you to load different samples of request message where you can modify to suit your scenario
GET
GET https://httpbin.org/get
?name={{username}}
&address={{string}}
&order=5
&mode={{string}}
GET https://httpbin.org/get
?name={{username}}
&address={{string}}
&order=5
&mode={{string}}
Content-Type: application/xml
Authorization: {{ string }}
CustomHeader-1: {{ digit }}
CustomHeader-2: {{ filename }}
CustomHeader-3: {{ username }}
Upload files
POST image
POST https://httpbin.org/post HTTP/1.1
{{ image('option-file-name.png') }}
POST PDF
POST https://httpbin.org/post HTTP/1.1
{{ pdf('option-file-name.pdf') }}
POST naughty payloads
POST https://httpbin.org/post HTTP/1.1
{{ file('option-file-name.log') }}
POST your custom file content for example a CSV file
POST https://httpbin.org/post
x-ms-blob-type: BlockBlob
{{
'
string,username,password,filename,datetime
{{string}},{{username}},{{password}},{{filename}},{{datetime}}
{{string}},{{username}},{{password}},{{filename}},{{datetime}}
{{string}},{{username}},{{password}},{{filename}},{{datetime}}
{{string}},{{username}},{{password}},{{filename}},{{datetime}}
{{string}},{{username}},{{password}},{{filename}},{{datetime}}
{{string}},{{username}},{{password}},{{filename}},{{datetime}}
'
| myfile("batchfile.log")
}}
POST XML
POST https://httpbin.org/post
Content-Type: application/xml
{
<note>
<to>{{ username }}</to>
<from>{{ username }}</from>
<heading>{{ 'Reminder' | mutate }}</heading>
<body>{{ 'Don't forget me this weekend!' | mutate }}</body>
</note>
}
POST JSON
POST https://httpbin.org/post
Content-Type: application/json
{
"name": "john doe",
"info": {{ 'this custom input will be mutated by fuzzie' | mutate }}
}
GraphQL
POST https://spacex-production.up.railway.app/
X-REQUEST-TYPE: GraphQL
{
launchesPast(limit: 10) {
mission_name
launch_date_local
launch_site {
site_name_long
}
links {
article_link
video_link
}
rocket {
rocket_name
}
}
}