Of every tool in my recon toolkit, ffuf is the one I reach for most often. It’s fast, it’s flexible, and once you understand its FUZZ keyword pattern, you realize it’s not just a directory brute-forcer — it’s a general-purpose HTTP fuzzing engine that can hit virtually any part of a request: paths, parameters, headers, POST bodies, even the Host header for virtual host discovery.
What Is ffuf?
ffuf stands for “Fuzz Faster U Fool.” It’s written in Go, which is a big part of why it’s so much faster than older Perl/Python-based fuzzers like dirb — Go’s concurrency model lets it fire off hundreds of requests in parallel with low overhead.
At its core, ffuf takes a wordlist and a request template containing the placeholder FUZZ, substitutes each wordlist entry into that placeholder, sends the request, and reports back based on response size, status code, word count, or line count — letting you filter out the noise (like a wildcard “catch-all” 200 response) and zero in on real results.
How It Works Internally
ffuf’s architecture is straightforward but well engineered:
- Input layer: reads one or more wordlists (or generates values via input commands) and manages placeholder substitution.
- Job scheduler: a worker pool of goroutines sends requests concurrently, respecting the
-t(threads) and-p(delay) settings. - Matcher/filter engine: every response is evaluated against matcher (
-mc,-ms,-mw,-ml) and filter (-fc,-fs,-fw,-fl) rules before being shown or hidden. - Output layer: results can be streamed to console or exported as JSON, CSV, HTML, or markdown for reporting.
This matcher/filter separation is what makes ffuf so much smarter than naive brute-forcers — instead of just listing every response, you tell it “hide anything that returns exactly 4242 bytes” (a typical soft-404 page), and it automatically cleans up the noise.
Installation
Via Go (recommended, always gets the latest release):
go install github.com/ffuf/ffuf/v2@latest
Via apt on Kali:
sudo apt update
sudo apt install ffuf
Verify:
ffuf -V
Basic Syntax
ffuf -w <wordlist> -u <url_with_FUZZ_keyword>
Directory & File Discovery
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://192.168.56.101/FUZZ
Sample output:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0
________________________________________________
:: Method : GET
:: URL : http://192.168.56.101/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/common.txt
________________________________________________
admin [Status: 301, Size: 313, Words: 20, Lines: 10]
config.php [Status: 200, Size: 0, Words: 1, Lines: 1]
uploads [Status: 301, Size: 315, Words: 20, Lines: 10]
robots.txt [Status: 200, Size: 45, Words: 4, Lines: 3]
:: Progress: [4614/4614] :: Job [1/1] :: 812 req/sec :: Duration: [0:00:06] :: Errors: 0 ::
Filtering Out Noise (Wildcard Responses)
If a server returns a soft-404 (status 200 for everything), filter it out by size:
ffuf -w common.txt -u http://192.168.56.101/FUZZ -fs 4242
Or match only interesting status codes:
ffuf -w common.txt -u http://192.168.56.101/FUZZ -mc 200,301,302,403
Parameter Fuzzing
ffuf -w params.txt -u "http://192.168.56.101/search.php?FUZZ=test" -mc 200 -fs 1234
POST Body Fuzzing
ffuf -w passwords.txt -X POST -d "username=admin&password=FUZZ" \
-H "Content-Type: application/x-www-form-urlencoded" \
-u http://192.168.56.101/login.php -fc 401
Virtual Host Discovery
ffuf -w subdomains.txt -u http://192.168.56.101/ -H "Host: FUZZ.example.lab" -fs 4242
Recursive Scanning
ffuf -w common.txt -u http://192.168.56.101/FUZZ -recursion -recursion-depth 2
Extension Fuzzing
ffuf -w common.txt -u http://192.168.56.101/FUZZ -e .php,.bak,.txt,.zip
Output for Reporting
ffuf -w common.txt -u http://192.168.56.101/FUZZ -o results.json -of json
Real-World Use Case (Authorized Lab Only)
On a lab CTF-style box, I’ve used ffuf to first discover a hidden /backup/ directory that dirb missed because I combined -recursion with an extension list, revealing a .php.bak source file. Reading that backup file exposed hardcoded database credentials, which I then used (within the same authorized scope) to move laterally into the application’s admin panel.
Workflow Integration
- Amass/subfinder → passive subdomain enumeration, feeding a target list into ffuf’s vhost fuzzing.
- ffuf → directory/file discovery, parameter fuzzing, vhost discovery.
- Burp Suite → send interesting ffuf hits into Burp Repeater for manual follow-up.
- Nuclei → once ffuf surfaces endpoints, run template-based vulnerability checks against them.
Performance Optimization
- Increase threads with
-t(default 40) if the target and your network can handle it — I typically go up to 100-150 on internal lab targets. - Use
-rateto cap requests/sec when testing against rate-limited or fragile targets. - Use
-mode clusterbombor-mode pitchforkwhen fuzzing multipleFUZZpositions with multiple wordlists simultaneously.
Troubleshooting & Common Mistakes
- Getting thousands of false positives — you forgot to filter the wildcard/soft-404 response size; always do a baseline request to a random nonexistent path first.
- Too slow — check
-tisn’t left at a low default, and confirm you’re not hitting an unintentional rate limit or WAF throttling. - SSL errors on self-signed certs — add
-kto skip certificate verification in a lab context. - Recursive scans running forever — always set
-recursion-depthto bound scope.
Best Practices
- Always baseline the target’s 404 behavior before fuzzing.
- Match scope and rate limits to what’s authorized — aggressive fuzzing can degrade production-like lab services.
- Save results to JSON for later parsing/reporting rather than relying on scrollback.
FAQ
How is ffuf different from dirb or dirbuster? ffuf is significantly faster due to Go’s concurrency, and it’s far more flexible — it can fuzz any part of an HTTP request, not just the URL path, and has a much more powerful matcher/filter system.
Can ffuf fuzz JSON APIs? Yes — put FUZZ inside the -d JSON body and set the appropriate Content-Type header.
Does ffuf support proxies like Burp? Yes, via -x http://127.0.0.1:8080, which is useful for capturing every fuzzed request in Burp’s history.
Summary
ffuf has become close to the default choice for web fuzzing in modern pentesting workflows because of its speed, flexible FUZZ placeholder system, and strong matcher/filter engine that cuts through response noise quickly. Once you get comfortable with its matcher/filter flags, it becomes far more than a directory brute-forcer — it’s a general-purpose fuzzing engine for almost any part of an HTTP request.
References
Kali Linux Tools: https://www.kali.org/tools/ffuf/
Official GitHub repository: https://github.com/ffuf/ffuf
ffuf documentation wiki: https://github.com/ffuf/ffuf/wiki
