Table of Contents
What Is Fuzzing?
Step 1: Install & Configure Ffuf
The only requirement to run ffuf is having Go installed, which can easily be done on Kali with the package manager.
~$ sudo apt install golang
Reading package lists... Done
Building dependency tree
Reading state information... Done
golang is already the newest version (2:1.14~2).
0 upgraded, 0 newly installed, 0 to remove and 17 not upgraded.
Next, grab the latest ffuf release from GitHub. At the time of writing, this is version 1.1.0. We can use wget to download it.
~$ wget https://github.com/ffuf/ffuf/releases/download/v1.1.0/ffuf_1.1.0_linux_amd64.tar.gz
--2020-08-27 11:36:41-- https://github.com/ffuf/ffuf/releases/download/v1.1.0/ffuf_1.1.0_linux_amd64.tar.gz
Resolving github.com (github.com)... 140.82.112.4
Connecting to github.com (github.com)|140.82.112.4|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://github-production-release-asset-2e65be.s3.amazonaws.com/156681830/192d4700-cceb-11ea-97f4-adcd48470676?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163641Z&X-Amz-Expires=300&X-Amz-Signature=493a4881a3e960fb7c29baa5ee999efe96bbb5414fd122355b1ec19fe65d1214&X-Amz-SignedHeaders=host&actor_id=0&repo_id=156681830&response-content-disposition=attachment%3B%20filename%3Dffuf_1.1.0_linux_amd64.tar.gz&response-content-type=application%2Foctet-stream [following]
--2020-08-27 11:36:41-- https://github-production-release-asset-2e65be.s3.amazonaws.com/156681830/192d4700-cceb-11ea-97f4-adcd48470676?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163641Z&X-Amz-Expires=300&X-Amz-Signature=493a4881a3e960fb7c29baa5ee999efe96bbb5414fd122355b1ec19fe65d1214&X-Amz-SignedHeaders=host&actor_id=0&repo_id=156681830&response-content-disposition=attachment%3B%20filename%3Dffuf_1.1.0_linux_amd64.tar.gz&response-content-type=application%2Foctet-stream
Resolving github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)... 52.217.37.12
Connecting to github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)|52.217.37.12|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3101002 (3.0M) [application/octet-stream]
Saving to: ‘ffuf_1.1.0_linux_amd64.tar.gz’
ffuf_1.1.0_linux_amd64.tar.gz 100%[========================================================================================================================================>] 2.96M 5.74MB/s in 0.5s
2020-08-27 11:36:42 (5.74 MB/s) - ‘ffuf_1.1.0_linux_amd64.tar.gz’ saved [3101002/3101002]
Now we need to extract the contents of the archive.
~$ tar xzf ffuf_1.1.0_linux_amd64.tar.gz
We should now have the ffuf executable in the current working directory, and we can run it with the dot-slash command.
~$ ./ffuf
Encountered error(s): 2 errors occured.
* -u flag or -request flag is required
* Either -w or --input-cmd flag is required
Fuzz Faster U Fool - v1.1.0
HTTP OPTIONS:
-H Header `"Name: Value"`, separated by colon. Multiple -H flags are accepted.
-X HTTP method to use (default: GET)
-b Cookie data `"NAME1=VALUE1; NAME2=VALUE2"` for copy as curl functionality.
-d POST data
-ignore-body Do not fetch the response content. (default: false)
-r Follow redirects (default: false)
-recursion Scan recursively. Only FUZZ keyword is supported, and URL (-u) has to end in it. (default: false)
-recursion-depth Maximum recursion depth. (default: 0)
-replay-proxy Replay matched requests using this proxy.
-timeout HTTP request timeout in seconds. (default: 10)
-u Target URL
-x HTTP Proxy URL
GENERAL OPTIONS:
-V Show version information. (default: false)
-ac Automatically calibrate filtering options (default: false)
-acc Custom auto-calibration string. Can be used multiple times. Implies -ac
-c Colorize output. (default: false)
-maxtime Maximum running time in seconds for entire process. (default: 0)
-maxtime-job Maximum running time in seconds per job. (default: 0)
-p Seconds of `delay` between requests, or a range of random delay. For example "0.1" or "0.1-2.0"
-s Do not print additional information (silent mode) (default: false)
-sa Stop on all error cases. Implies -sf and -se. (default: false)
-se Stop on spurious errors (default: false)
-sf Stop when > 95% of responses return 403 Forbidden (default: false)
-t Number of concurrent threads. (default: 40)
-v Verbose output, printing full URL and redirect location (if any) with the results. (default: false)
...
Running it without any arguments will print the help information and some usage examples. Now let’s say we wanted to be able to run this tool from anywhere — all we need to do is move ffuf to any directory in our path.
~$ sudo cp ffuf /usr/local/bin/
Now we can run it from anywhere without the need to have it in the current directory.
~$ ffuf -V
ffuf version: 1.1.0
The last step to get up and running is optional. Having a good set of wordlists is essential for any security professional, and there is a collection called SecLists that has just about anything you need. It is available on GitHub, but we can also install it locally on our machine.
~$ sudo apt install seclists
Step 2: Perform Some Basic Fuzzing
At the most basic level, we can use ffuf to fuzz for hidden directories or files. There are tools like gobuster out there that are made for this specific purpose, but using something like ffuf has its use cases.
For example, let’s say you’re testing a website that has some sort of rate-limiting in place. With other tools, it can sometimes be challenging to get them to go slower, and this is precisely where tools like ffuf come into play since we can more finely control the rate and timing options. More on that later.
Simply provide a wordlist with the -w flag, the URL with the -u flag, and put FUZZ where we want to insert our fuzzing.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
config [Status: 301, Size: 319, Words: 21, Lines: 10]
docs [Status: 301, Size: 317, Words: 21, Lines: 10]
about [Status: 302, Size: 0, Words: 1, Lines: 1]
external [Status: 301, Size: 321, Words: 21, Lines: 10]
favicon.ico [Status: 200, Size: 1405, Words: 5, Lines: 2]
php.ini [Status: 200, Size: 148, Words: 17, Lines: 5]
index [Status: 302, Size: 0, Words: 1, Lines: 1]
robots [Status: 200, Size: 26, Words: 3, Lines: 2]
robots.txt [Status: 200, Size: 26, Words: 3, Lines: 2]
instructions [Status: 302, Size: 0, Words: 1, Lines: 1]
index.php [Status: 302, Size: 0, Words: 1, Lines: 1]
logout [Status: 302, Size: 0, Words: 1, Lines: 1]
phpinfo [Status: 302, Size: 0, Words: 1, Lines: 1]
login [Status: 200, Size: 1289, Words: 83, Lines: 66]
phpinfo.php [Status: 302, Size: 0, Words: 1, Lines: 1]
setup [Status: 200, Size: 3549, Words: 182, Lines: 81]
security [Status: 302, Size: 0, Words: 1, Lines: 1]
:: Progress: [4658/4658] :: Job [1/1] :: 388 req/sec :: Duration: [0:00:12] :: Errors: 0 ::
We can also include any necessary cookies in our request using the -b flag.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -b "PHPSESSID=a4885a1d1802209109693054d94ae214; security=low" -u http://10.10.0.50/dvwa/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Header : Cookie: PHPSESSID=a4885a1d1802209109693054d94ae214; security=low
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
...
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -H "Host: 10.10.0.50" -u http://10.10.0.50/dvwa/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Header : Host: 10.10.0.50
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
...
Instead of doing the default GET request, we can also send POST requests. Use the -X flag to specify the request type, in this case, POST, and include the data for the request with the -d flag.
~$ ffuf -w /usr/share/seclists/Passwords/darkweb2017-top100.txt -X POST -d "username=admin\&password=FUZZ\&Login=Login" -u http://10.10.0.50/dvwa/login.php
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : POST
:: URL : http://10.10.0.50/dvwa/login.php
:: Wordlist : FUZZ: /usr/share/seclists/Passwords/darkweb2017-top100.txt
:: Data : username=admin\&password=FUZZ\&Login=Login
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
123abc [Status: 200, Size: 1289, Words: 83, Lines: 66]
123456789 [Status: 200, Size: 1289, Words: 83, Lines: 66]
123321 [Status: 200, Size: 1289, Words: 83, Lines: 66]
...
We can use ffuf to fuzz for parameters as well — simply replace the parameter name to fuzz for with the FUZZ keyword.
~$ ffuf -w /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt -u http://10.10.0.50/dvwa/instructions.php?FUZZ=readme
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/instructions.php?FUZZ=readme
:: Wordlist : FUZZ: /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
!.htpasswd [Status: 302, Size: 0, Words: 1, Lines: 1]
.AppleDouble [Status: 302, Size: 0, Words: 1, Lines: 1]
.AppleDesktop [Status: 302, Size: 0, Words: 1, Lines: 1]
.bak [Status: 302, Size: 0, Words: 1, Lines: 1]
!.htaccess [Status: 302, Size: 0, Words: 1, Lines: 1]
...
Fuzzing for parameter values works the same way.
~$ ffuf -w /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt -u http://10.10.0.50/dvwa/instructions.php?doc=FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/instructions.php?FUZZ=readme
:: Wordlist : FUZZ: /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
!.htpasswd [Status: 302, Size: 0, Words: 1, Lines: 1]
.AppleDouble [Status: 302, Size: 0, Words: 1, Lines: 1]
.AppleDesktop [Status: 302, Size: 0, Words: 1, Lines: 1]
.bak [Status: 302, Size: 0, Words: 1, Lines: 1]
!.htaccess [Status: 302, Size: 0, Words: 1, Lines: 1]
...
Step 3: Try the Filtering & Timing Options
Ffuf can perform matching and filtering, depending on what you want to see in the results. For instance, if we only wanted to see results with a 200 status code, we could use the -mc switch to match.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -mc 200
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200
________________________________________________
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
favicon.ico [Status: 200, Size: 1405, Words: 5, Lines: 2]
php.ini [Status: 200, Size: 148, Words: 17, Lines: 5]
robots [Status: 200, Size: 26, Words: 3, Lines: 2]
robots.txt [Status: 200, Size: 26, Words: 3, Lines: 2]
...
On the flip side, we can also filter certain status codes using the -fc switch.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -fc 403
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
:: Filter : Response status: 403
________________________________________________
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
config [Status: 301, Size: 319, Words: 21, Lines: 10]
docs [Status: 301, Size: 317, Words: 21, Lines: 10]
external [Status: 301, Size: 321, Words: 21, Lines: 10]
favicon.ico [Status: 200, Size: 1405, Words: 5, Lines: 2]
php.ini [Status: 200, Size: 148, Words: 17, Lines: 5]
about [Status: 302, Size: 0, Words: 1, Lines: 1]
...
This will hide any results with a 403 status code. Multiple codes for wither matching or filtering can be used as long as they are comma-separated.
We can perform similar matching and filtering with request size and the number of words or lines. For example, to filter any results returning with request size 0, do the following.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -fs 0
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
:: Filter : Response size: 0
________________________________________________
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
config [Status: 301, Size: 319, Words: 21, Lines: 10]
docs [Status: 301, Size: 317, Words: 21, Lines: 10]
external [Status: 301, Size: 321, Words: 21, Lines: 10]
favicon.ico [Status: 200, Size: 1405, Words: 5, Lines: 2]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
php.ini [Status: 200, Size: 148, Words: 17, Lines: 5]
...
Ffuf has some additional features to control timing of requests as well. To set a timeout for each individual request, use the -timeout option (default is 10 seconds).
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -timeout 5
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 5
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
config [Status: 301, Size: 319, Words: 21, Lines: 10]
...
We can also set a delay between each request with the -p flag. For example, to delay 2 seconds between requests, try the following.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -p 2
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Delay : 2.00 seconds
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
...
Another handy feature is the ability to set a maximum time for ffuf to run — this is useful when using a large wordlist, and you don’t want to wait around all day for it to finish. Use the -maxtime option followed by the number of seconds for ffuf to run before exiting.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -maxtime 60
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
...
If we want to run faster, we can set the number of threads to use (default is 40).
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -t 60
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 60
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
config [Status: 301, Size: 319, Words: 21, Lines: 10]
...
For simpler viewing in the terminal, we can use the -s flag to only print the found objects and none of the other noise.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -s
.htpasswd
README
config
docs
external
favicon.ico
about
...
This is useful if we wanted to grep any output or use the results in a script or something, not to mention it’s just a bit cleaner.
We can also save any results to a file using the -o switch.
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -o results.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Output file : results.txt
:: File format : json
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
...
The default format is JSON, but we can change that with the -of flag. For example, to save the results in HTML format, try:
~$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.0.50/dvwa/FUZZ -o results.txt -of html
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://10.10.0.50/dvwa/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Output file : results.txt
:: File format : html
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.htaccess [Status: 403, Size: 297, Words: 22, Lines: 11]
.hta [Status: 403, Size: 292, Words: 22, Lines: 11]
.htpasswd [Status: 403, Size: 297, Words: 22, Lines: 11]
README [Status: 200, Size: 4934, Words: 637, Lines: 120]
...
Wrapping up
In this tutorial, we learned a bit about fuzzing and how to use a tool called ffuf to fuzz for directories, parameters, and more. First, we installed the tool and configured it to run on our system. Next, we covered some basic fuzzing, including fuzzing GET requests, POST requests, and parameters. Finally, we concluded with some filtering and timing options for more fine-grained control. Hopefully, you find ffuf as valuable as I do!