ffuf
Fast web fuzzer written in Go. Discovers hidden directories, files, subdomains, and parameters by brute-forcing with wordlists. The FUZZ keyword goes wherever you want to fuzz.
What is it?
ffuf (Fuzz Faster U Fool) sends HTTP requests with a wordlist, replacing the keyword FUZZ with each word. It's the go-to tool for web content discovery, finding hidden pages, directories, API endpoints, subdomains, and parameters that aren't linked from the visible site.
ffuf is faster than Gobuster, more flexible than dirb, and handles edge cases better. It's the standard for CPTS web enumeration.
Run this first
FUZZ is the placeholder ffuf replaces with every word from the wordlist. Put it where the unknown part goes.
$ ffuf -u http://10.10.10.10/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
-uis the URL, with FUZZ where the guesses go.-wis the wordlist.
ffuf already hides 404s. Check the first few results: if everything has the same size, the server returns one page for every missing path, so filter that size with -fs or let ffuf work it out with -ac. Add -e .php,.txt to look for files as well as directories.
admin [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 112ms] <-- redirect, a real directory robots.txt [Status: 200, Size: 42, Words: 5, Lines: 3, Duration: 87ms] backup [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 95ms] <-- exists but forbidden, still worth noting :: Progress: [87664/87664] :: Job [1/1] :: 320 req/sec :: Duration: [0:04:33] :: Errors: 0 ::
When do you use it?
- Nmap shows port 80/443 open → directory and file fuzzing is always step 1 for web
- You found a web app → fuzz for hidden pages, admin panels, backup files
- You suspect virtual hosts → subdomain/vhost fuzzing reveals hidden sites on the same server
- You found an API → fuzz for undocumented endpoints
- You need to find parameters → parameter fuzzing for GET/POST params
- You found a login page → fuzz for default creds or valid usernames
How do you use it?
Directory fuzzing
# Basic directory fuzzing $ ffuf -u http://10.10.10.10/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt # With extensions (find files, not just directories) $ ffuf -u http://10.10.10.10/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -e .php,.html,.txt,.bak,.old,.conf # 404s are already hidden: the default matcher is 200-299,301,302,307,401,403,405,500 # Use -fc to drop codes from that list, for example a flood of 403s $ ffuf -u http://10.10.10.10/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -fc 403 # Recursive fuzzing (fuzz inside found directories) $ ffuf -u http://10.10.10.10/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -recursion -recursion-depth 2
Subdomain / vhost fuzzing
# Subdomain fuzzing via Host header $ ffuf -u http://10.10.10.10 -H "Host: FUZZ.corp.local" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt # The server responds differently for valid vhosts vs invalid ones # You'll get a flood of results, filter by response size to find unique ones: $ ffuf -u http://10.10.10.10 -H "Host: FUZZ.corp.local" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs 1234 # -fs 1234 = filter out responses of size 1234 (the default page size) # Run once without -fs, note the common response size, then add -fs to filter it
Many web servers serve different content based on the Host header. A server at 10.10.10.10 might serve the default page for unknown hosts, but a completely different site for admin.corp.local. Vhost fuzzing finds these hidden sites. Always add discovered hostnames to /etc/hosts.
Filtering results
# Filter by status code (exclude 403s; 404s never show by default, add -mc all to see them) $ ffuf -u http://target/FUZZ -w wordlist.txt -fc 403 # Let ffuf calibrate the filter itself, which helps when the server returns 200 for missing pages $ ffuf -u http://target/FUZZ -w wordlist.txt -ac # Filter by response size (exclude pages of size 1234) $ ffuf -u http://target/FUZZ -w wordlist.txt -fs 1234 # Filter by word count $ ffuf -u http://target/FUZZ -w wordlist.txt -fw 42 # Filter by line count $ ffuf -u http://target/FUZZ -w wordlist.txt -fl 10 # Match ONLY specific status codes (only show 200 and 301) $ ffuf -u http://target/FUZZ -w wordlist.txt -mc 200,301
POST request fuzzing (login brute-force)
# Fuzz a login form, try passwords for a known user $ ffuf -u http://target/login -X POST -d "username=admin&password=FUZZ" -H "Content-Type: application/x-www-form-urlencoded" -w /usr/share/wordlists/rockyou.txt -fc 401 # Fuzz both username and password (two FUZZ keywords) $ ffuf -u http://target/login -X POST -d "username=W1&password=W2" -H "Content-Type: application/x-www-form-urlencoded" -w users.txt:W1 -w passwords.txt:W2 -fc 401 # W1 and W2 are custom keyword names for multiple wordlists
Parameter fuzzing
# Fuzz GET parameters $ ffuf -u 'http://target/page?FUZZ=test' -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt -fs 1234 # Fuzz POST parameters $ ffuf -u http://target/page -X POST -d "FUZZ=test" -H "Content-Type: application/x-www-form-urlencoded" -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt -fs 1234
Useful flags
# Throttle speed (for rate-limited targets) $ ffuf -u http://target/FUZZ -w wordlist.txt -rate 100 # Set threads (default 40) $ ffuf -u http://target/FUZZ -w wordlist.txt -t 80 # Add a cookie (for authenticated fuzzing) $ ffuf -u http://target/FUZZ -w wordlist.txt -b "session=abc123" # Output to file $ ffuf -u http://target/FUZZ -w wordlist.txt -o results.json -of json # Follow redirects $ ffuf -u http://target/FUZZ -w wordlist.txt -r # Use a proxy (route through Burp) $ ffuf -u http://target/FUZZ -w wordlist.txt -x http://127.0.0.1:8080
Which wordlists?
| Task | Wordlist (SecLists path) |
|---|---|
| Directory fuzzing | Discovery/Web-Content/directory-list-2.3-small.txt (fast) or -medium.txt (thorough) |
| File discovery | Discovery/Web-Content/raft-medium-files.txt |
| Subdomain/vhost | Discovery/DNS/subdomains-top1million-5000.txt or -20000.txt |
| Parameters | Discovery/Web-Content/burp-parameter-names.txt |
| Login brute-force | /usr/share/wordlists/rockyou.txt |
| API endpoints | Discovery/Web-Content/api/objects.txt |
What do you do with the output?
- Found directories: Browse them, look for sensitive files, check for directory listing
- Found .bak / .old / .conf files: Download them: they often contain credentials or configuration
- Found admin panels: Try default credentials, check for auth bypass
- Found subdomains: Add to
/etc/hostsand enumerate each one separately - Found hidden parameters: Test for injection (SQLi, XSS, SSRF, LFI), sqlmap, Burp Suite
- Found API endpoints: Check for IDOR, auth bypass, information disclosure
Common mistakes
- Not filtering results: A custom 404 page returns 200 for everything. Always check the first results, if everything returns the same size, filter with
-fs - Forgetting extensions:
/adminmight 404 but/admin.phpexists. Always add-e .php,.html,.txt,.asp,.aspxbased on the tech stack - Not fuzzing vhosts: A server might only show a default page on the IP. Vhost fuzzing can reveal entirely different applications
- Using the wrong wordlist:
directory-list-2.3-small.txtis a good start. If it finds nothing, try-medium.txtor a different list entirely - Forgetting to add subdomains to /etc/hosts: After finding
dev.corp.local, add it:echo "10.10.10.10 dev.corp.local" >> /etc/hosts - Too many threads on slow targets: Default 40 threads can overwhelm some targets. Use
-rate 50or-t 10if getting errors
Check yourself
Answer each question out loud or on paper first, then open it. Retrieving the answer teaches you more than rereading the page.
Every result has status 200 and the same size. What is happening, and what do you do?
-fs, or use -ac to let ffuf calibrate the filter.Why do you need the -e flag, and what is an example?
/admin may return 404 while /admin.php exists. -e .php,.html,.txt makes ffuf also try each word with those extensions.A server shows only a default page on its IP address. What else can you fuzz?
-H "Host: FUZZ.corp.local" and filter out the default response size. One server can host different applications by hostname.Which status codes does ffuf show by default, and which flag shows the 404s?
-mc all shows every code, including 404.The target returns errors or slows down. What do you change?
-rate 50 or fewer threads such as -t 10. The default is 40 threads.