ffuf (Fuzz Faster U Fool) is a fast web fuzzer written in Go. The core concept is the FUZZ keyword — place it anywhere in a URL, header, or request body, and ffuf replaces it with each line from a wordlist. Use it for directory brute forcing, virtual host discovery, and parameter enumeration. The -ac (auto-calibrate) flag handles custom 404 pages automatically.
Tool Card — ffuf
| Name | ffuf (Fuzz Faster U Fool) |
| Language | Go |
| Author | joohoi |
| GitHub | github.com/ffuf/ffuf |
| Install (Kali) | apt install ffuf |
| Primary Use | Web content discovery (directories, vhosts, parameters) |
| Key Feature | FUZZ keyword — place anywhere in request |
| Wordlists | SecLists (github.com/danielmiessler/SecLists) |
When you land on a web server in a CTF or engagement, the first question is: what’s actually here? The web server might have dozens of directories, files, and virtual hosts that aren’t linked anywhere. ffuf’s job is to find them by trying every entry in a wordlist and reporting back what exists.
The FUZZ keyword is what makes ffuf flexible. Unlike tools with fixed operation modes, ffuf lets you place FUZZ anywhere — in the path, in a header, in POST body data, in query parameters. One tool, one paradigm, multiple use cases.
Installation and Setup
$ install ffuf# Kali / Debian / Ubuntu
sudo apt update && sudo apt install ffuf -y
# From source (latest version, recommended for active engagements)
go install github.com/ffuf/ffuf/v2@latest
# Verify
ffuf -V
SecLists Wordlists
ffuf needs a wordlist. SecLists is the standard collection for web fuzzing:
$ install seclists# Kali
sudo apt install seclists
# Manual
git clone https://github.com/danielmiessler/SecLists /usr/share/seclists
Key SecLists paths for web fuzzing:
/usr/share/seclists/Discovery/Web-Content/common.txt— 4,614 entries, fast baseline/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt— 220,560 entries, thorough/usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt— 30k unique directories/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt— virtual host fuzzing/usr/share/seclists/Discovery/Web-Content/web-extensions.txt— file extension list
Core Flags Reference
| Flag | Purpose | Example |
|---|---|---|
-u | Target URL (contains FUZZ) | -u http://target.com/FUZZ |
-w | Wordlist path; optionally label with :NAME | -w /path/wordlist.txt:FUZZ |
-c | Colorize output | -c |
-t | Threads (default: 40) | -t 50 |
-e | File extensions to append to FUZZ value | -e .php,.html,.txt |
-r | Follow redirects | -r |
-ac | Auto-calibrate response filtering | -ac |
-mc | Match HTTP status codes | -mc 200,301,302,403 |
-fc | Filter HTTP status codes (exclude) | -fc 404 |
-ms | Match response size (bytes) | -ms 1234 |
-fs | Filter response size (exclude) | -fs 1234 |
-ml | Match response line count | -ml 42 |
-fl | Filter response line count | -fl 42 |
-mr | Match regex in response body | -mr "Welcome" |
-fr | Filter regex in response body | -fr "Not Found" |
-H | Custom header (repeatable) | -H "Host: FUZZ.target.com" |
-b | Cookie(s) | -b "session=abc123" |
-X | HTTP method | -X POST |
-d | POST data body | -d "user=FUZZ&pass=test" |
-o | Output file | -o results.json |
-of | Output format | -of json |
-recursion | Recursive fuzzing on found dirs | -recursion |
-recursion-depth | Max recursion depth | -recursion-depth 2 |
-rate | Requests per second limit | -rate 100 |
-p | Delay between requests | -p 0.1 |
-timeout | HTTP timeout in seconds | -timeout 10 |
-ic | Ignore comments in wordlist | -ic |
-v | Verbose output (show full URL) | -v |
-s | Silent mode (no header, no progress) | -s |
Directory and File Fuzzing
The standard starting point — place FUZZ in the URL path and let ffuf try every word in the list:
$ basic directory fuzzingffuf -u http://target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -c -mc 200,301,302,403
Adding File Extensions
Use -e to append extensions to each wordlist entry. ffuf tries admin, admin.php, admin.html, and admin.txt for each word:
ffuf -u http://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-e .php,.html,.txt,.bak,.old \
-c -mc 200,301,302,403 \
-ic
-ic ignores comment lines in wordlists (lines starting with #). SecLists files include comment headers that would otherwise generate bogus requests.Recursive Fuzzing
When ffuf finds a directory, -recursion automatically fuzzes inside it. Useful when you need depth but can be slow — use -recursion-depth to limit how far it goes:
ffuf -u http://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-c -mc 200,301,302,403 \
-recursion \
-recursion-depth 2
Filtering Results
Filtering is the skill that separates useful ffuf output from noise. Two approaches: match (show only) and filter (exclude):
-mc — status codes-ms — response size-ml — line count-mw — word count-mr — regex match
-fc — status codes-fs — response size-fl — line count-fw — word count-fr — regex match
Filtering by Response Size
When a server returns HTTP 200 for all requests (custom 404 page), filter by the size of that default response. First, make a request to a nonexistent path and check its size. Then filter that size:
$ filter by size after manual check# Check default response size
curl -s http://target.com/doesnotexist123 | wc -c
# Returns: 1587
# Filter that size from ffuf
ffuf -u http://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-c -fs 1587
Filtering with Regex
$ filter responses containing specific text# Exclude responses containing "Page Not Found"
ffuf -u http://target.com/FUZZ \
-w wordlist.txt \
-fr "Page Not Found"
# Match only responses containing "admin" in body
ffuf -u http://target.com/FUZZ \
-w wordlist.txt \
-mr "admin panel"
Virtual Host Fuzzing
Virtual host fuzzing discovers subdomains served by the same web server. The technique: place FUZZ in the Host header and watch for responses that differ from the default. Common in CTF machines where the IP resolves to a main site but hides an admin panel on a subdomain.
ffuf -u http://10.10.10.X/ \
-H "Host: FUZZ.target.htb" \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-c \
-ac
-ac flag auto-calibrates by sending requests with random hostnames first. It learns what the default (no match) response looks like and filters it automatically. This is the cleanest approach for vhost fuzzing.If auto-calibration doesn’t work cleanly — make a request with a fake hostname, check the response size, and filter it manually:
$ vhost fuzzing with manual size filter# Find default response size
curl -s -o /dev/null -w "%{size_download}" -H "Host: notasubdomain.target.htb" http://10.10.10.X/
# Returns: 612
# Run ffuf with size filter
ffuf -u http://10.10.10.X/ \
-H "Host: FUZZ.target.htb" \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-c -fs 612
/etc/hosts: echo "10.10.10.X admin.target.htb dev.target.htb" | sudo tee -a /etc/hostsPOST Data and Parameter Fuzzing
POST Body Fuzzing
Use -X POST and -d to fuzz POST data. Common for username enumeration or form fields:
ffuf -u http://target.com/login \
-X POST \
-d "username=FUZZ&password=wrongpassword" \
-H "Content-Type: application/x-www-form-urlencoded" \
-w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
-c -fr "Invalid username"
GET Parameter Discovery
Discover hidden GET parameters by placing FUZZ in the query string key position:
$ GET parameter name fuzzingffuf -u "http://target.com/page?FUZZ=test" \
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-c -fs 1234 -mc 200
Multi-Wordlist Fuzzing (FUZZ + W2)
When you need to fuzz two positions simultaneously — like testing all username/password combinations in a small set — use named keywords:
$ multi-wordlist (credential spray)ffuf -u http://target.com/login \
-X POST \
-d "user=USER&pass=PASS" \
-H "Content-Type: application/x-www-form-urlencoded" \
-w /tmp/users.txt:USER \
-w /tmp/passwords.txt:PASS \
-c -mr "Welcome"
Auto-Calibration for Custom 404 Pages
Many web applications return HTTP 200 with a “Page Not Found” or “Error” page instead of a proper 404 response. Standard status code matching (-mc 200) would flag every single request as a hit. -ac solves this automatically:
ffuf -u http://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-c \
-ac
What -ac does internally: before the main scan starts, ffuf sends several requests with random FUZZ values (e.g., abc123xyz789). It records the status code, response size, word count, and line count of these “not found” responses. Then, during the real scan, it filters out any response that matches this baseline profile. The calibration adapts per-scan — no manual size-checking needed.
Auto-calibration works well when the custom 404 responses are consistent. If the application returns variable-length error pages (e.g., error messages that include the attempted URL), auto-calibration may not filter perfectly — in that case, combine with -fr regex filtering.
Output and Saving Results
$ save results in JSON formatffuf -u http://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-c -ac \
-o results.json -of json
Output formats: json, ejson (extended JSON), html, md (markdown), csv, ecsv. JSON is the most useful for piping into other tools or scripts:
cat results.json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data.get('results', []):
print(r['url'])
"
Defensive Context
What ffuf traffic looks like: ffuf generates a high volume of HTTP requests to paths that don’t exist. In access logs, this appears as a flood of 404 or 403 responses from a single IP in a short time window. Any WAF or IDS with rate-based signatures will catch this quickly. The -rate and -p flags exist partly to slow requests below detection thresholds on engaged targets.
What to do on the blue side: Web application firewalls (WAFs) can detect and block directory brute-force patterns by tracking request volume per IP and triggering on excessive 404/403 rates. Rate limiting at the application or CDN layer (Cloudflare, AWS WAF rules) reduces the effectiveness of tools like ffuf against production assets. For internal networks, web server access logs should be monitored for bursts of 404s against non-existent paths.
What gets found that shouldn’t be there: The directories and files ffuf commonly surfaces — /backup, /.git, /admin, /.env, /config.php.bak — represent forgotten or inadvertently exposed resources. Restricting web server directory listing, returning proper 404 status codes, and reviewing what’s accessible in the web root before deployment reduces the attack surface that tools like ffuf exploit.
🔍 Things to Consider
The power of ffuf isn’t in how fast it sends requests — it’s in how well you filter the responses. The difference between an unusable wall of output and a clean hit list is knowing which combination of -mc, -fs, -fc, and -ac applies to the specific application you’re fuzzing. The first few seconds of looking at a target’s response behavior should inform your filter choices before you run the full wordlist. Also worth noting: the wordlist matters as much as the tool. directory-list-2.3-medium.txt finds more than common.txt, but takes longer. Match the wordlist depth to the time and sensitivity of the engagement.
~Cipherceval
Frequently Asked Questions
What is ffuf used for in penetration testing?
ffuf is a web fuzzer used for directory and file brute forcing (finding hidden paths), virtual host enumeration (discovering subdomains on the same IP), GET/POST parameter discovery, and header fuzzing. The FUZZ keyword can be placed anywhere in a request — URL, Host header, request body, query parameters — making it more flexible than tools with fixed operation modes like older versions of gobuster.
How does ffuf auto-calibration work?
The -ac flag sends several warmup requests with random strings before the main scan. It records the status code, size, word count, and line count of these “not found” responses. During the real scan, responses matching this baseline profile are automatically filtered. This is particularly useful when a server returns HTTP 200 for missing pages (custom 404 pages) rather than the standard 404 status code.
What wordlists work best with ffuf?
SecLists (install with apt install seclists on Kali, path: /usr/share/seclists/) is the standard collection. For directory fuzzing: Discovery/Web-Content/common.txt (4,614 entries, fast) or Discovery/Web-Content/directory-list-2.3-medium.txt (220k entries, thorough). For virtual host fuzzing: Discovery/DNS/subdomains-top1million-5000.txt. The right wordlist depends on the time budget and engagement sensitivity.
What is the difference between -mc and -fc in ffuf?
-mc (match code) shows only responses with specified HTTP status codes. -fc (filter code) hides responses with specified codes. They are opposites: -mc 200,301,302,403 shows only those codes; -fc 404 hides 404s and shows everything else. For most directory fuzzing, -mc 200,301,302,403 is a reasonable starting filter — 403 is worth keeping because it indicates a path exists but requires authorization.
How do you fuzz virtual hosts with ffuf?
Place the FUZZ keyword in the Host header: ffuf -u http://TARGET_IP/ -H "Host: FUZZ.target.com" -w subdomains.txt -ac. The -ac flag auto-calibrates to filter the default response. Alternatively, find the default response size with curl -s -o /dev/null -w "%{size_download}" -H "Host: fakehost.target.com" http://TARGET_IP/ and filter with -fs SIZE. Add discovered subdomains to /etc/hosts before browsing them.
See also: gobuster vs ffuf — which tool fits which situation. For passive recon before you start fuzzing: theHarvester OSINT Tutorial.
Stay vigilant, stay curious, and update your stuff.
— Cipherceval / Forgebound Research
Exploit Brokers by Forgebound Research
Disclaimer: The content presented by Exploit Brokers by Forgebound Research is for educational and informational purposes only. Cipherceval is a cybersecurity educator and commentator — not your personal security consultant, legal counsel, or professional advisor. Always consult qualified professionals for decisions affecting your systems and security posture.
Technical Disclaimer: The techniques demonstrated here require explicit written authorization before use on real systems. Unauthorized access to computer systems is illegal under the Computer Fraud and Abuse Act (CFAA) in the US and similar legislation worldwide.
Leave a Reply