1. What Are Gobuster & Ffuf? (And When to Use Each)
You’ve mapped a target web application, intercepted some traffic in Burp Suite, and found a few visible pages. But hidden behind the surface are admin panels, backup files, staging environments, API endpoints, and forgotten directories that no link on the page points to. Finding those is the job of web fuzzing tools — and Gobuster and ffuf are the two tools every pentester needs to know.
Both tools are written in Go, both are blazingly fast, and both work by sending thousands of HTTP requests with different paths or values and analysing what comes back. The key difference is in scope and flexibility.
|
|
Gobuster |
ffuf |
|
Primary purpose |
Directory/file busting, DNS, vhosts — optimised for brute-force discovery |
General web fuzzer — fuzz anything: URLs, headers, parameters, POST data, cookies |
|
Keyword/position |
Appends to URL path automatically (no placeholder needed) |
Uses FUZZ keyword — place it anywhere in the request |
|
Learning curve |
Simpler — fewer flags, more opinionated |
More powerful — but requires understanding filters to get clean output |
|
Filtering |
Basic status code filtering |
Extensive — filter by status, size, words, lines, regex, time |
|
Recursion |
Not built-in (run again manually on found paths) |
Yes — -recursion and -recursion-depth flags |
|
Multiple wordlists |
Single wordlist per run |
Multiple simultaneous wordlists with named keywords |
|
Best for |
Quick initial recon, DNS enum, vhost discovery |
Parameter fuzzing, POST data, auth bypass, API testing, advanced filtering |
|
The rule of thumb Use Gobuster for a quick first sweep — it’s faster to type and great for the most common use case (directory busting). Switch to ffuf when you need to fuzz parameters, headers, POST data, or anything that requires a placeholder to be placed somewhere other than the end of a URL path. |
2. Installation & Setup
Kali Linux — both tools are pre-installed
|
# Update to latest versions sudo apt update && sudo apt install gobuster ffuf -y # Verify installations gobuster version ffuf -V |
Manual installation (any Linux / macOS)
|
# Gobuster — from Go binary go install github.com/OJ/gobuster/v3@latest # ffuf — from Go binary go install github.com/ffuf/ffuf/v2@latest # ffuf — from pre-built binary (Linux x64) wget https://github.com/ffuf/ffuf/releases/latest/download/ffuf_Linux_amd64.tar.gz tar -xvf ffuf_Linux_amd64.tar.gz chmod +x ffuf && sudo mv ffuf /usr/local/bin/ |
Windows
|
# Download gobuster from: https://github.com/OJ/gobuster/releases # Download ffuf from: https://github.com/ffuf/ffuf/releases # Extract ZIP and run from the extracted folder: gobuster.exe –help ffuf.exe -h |
Installing SecLists (essential wordlists)
|
# Kali Linux sudo apt install seclists -y # Installed to: /usr/share/seclists/ # Manual install git clone https://github.com/danielmiessler/SecLists /usr/share/seclists |
3. Wordlists: The Foundation of Good Fuzzing
Neither tool discovers directories by magic. They send every entry in a wordlist as a request and flag interesting responses. The quality of your wordlist is the single biggest factor in what you find.
Recommended wordlists by use case
|
Use case |
Wordlist |
Path (Kali) |
|
Directory/file discovery (fast) |
common.txt |
/usr/share/seclists/Discovery/Web-Content/common.txt |
|
Directory/file discovery (thorough) |
directory-list-2.3-medium.txt |
/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt |
|
Directory busting (large) |
raft-large-directories.txt |
/usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt |
|
File discovery (with extensions) |
raft-large-files.txt |
/usr/share/seclists/Discovery/Web-Content/raft-large-files.txt |
|
API endpoint discovery |
api/api-endpoints.txt |
/usr/share/seclists/Discovery/Web-Content/api/ |
|
Subdomain enumeration |
subdomains-top1million-20000.txt |
/usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt |
|
Vhost enumeration |
subdomains-top1million-5000.txt |
/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt |
|
Parameter name fuzzing |
burp-parameter-names.txt |
/usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt |
|
Backup & config files |
CommonBackdoors-PHP.fuzz.txt |
/usr/share/seclists/Discovery/Web-Content/ |
|
Password brute force (web forms) |
rockyou.txt |
/usr/share/wordlists/rockyou.txt |
Quick wordlist tips
• Start with common.txt (4,600 entries) for speed, then escalate to medium or large lists.
• Always add relevant file extensions with -x php,html,js,txt,bak,zip — raw directory busting misses files.
• Build a CeWL wordlist from the target site for targeted engagements:
|
cewl https://target.com -d 3 -m 5 -w custom_wordlist.txt |
4. Gobuster: All Modes & Flags — Complete Reference
Gobuster organises its functionality into modes. You choose the mode first, then apply flags specific to that mode.
Gobuster Modes
|
Mode |
Full name |
What it does |
|
dir |
Directory/file |
Brute-forces directories and files on web servers. The most used mode. |
|
dns |
DNS subdomain |
Discovers subdomains by brute-forcing DNS entries. |
|
vhost |
Virtual host |
Finds virtual hosts on a target server using the HTTP Host header. |
|
fuzz |
Fuzzing |
Replaces the FUZZ keyword anywhere in the URL, headers, or body. |
|
s3 |
AWS S3 |
Enumerates publicly accessible Amazon S3 buckets. |
|
gcs |
Google Cloud Storage |
Enumerates publicly accessible GCS buckets. |
|
tftp |
TFTP |
Enumerates files on TFTP servers (network device configs, etc.). |
Global Flags (apply to all modes)
|
Flag |
Description |
|
-w, –wordlist |
Path to the wordlist file. Required for all modes. |
|
-t, –threads |
Number of concurrent threads. Default: 10. Increase for speed (e.g., -t 50). |
|
-o, –output |
Write results to a file: -o results.txt |
|
-q, –quiet |
Suppress banner and noise. Show results only. |
|
-z, –no-progress |
Don’t show progress bar. Cleaner output for piping. |
|
-v, –verbose |
Verbose output. Shows errors and extra info. |
|
–delay |
Wait between requests to avoid rate-limiting: –delay 100ms |
|
–no-color |
Disable ANSI colour output. Useful when logging to file. |
|
–debug |
Print debug information. Useful for troubleshooting. |
dir Mode Flags
|
Flag |
Description |
|
-u, –url |
Target URL. Required. e.g., -u https://target.com |
|
-x, –extensions |
File extensions to append: -x php,html,js,txt,bak. Critical for finding files. |
|
-s, –status-codes |
Comma-separated list of status codes to treat as valid: -s 200,204,301,302,307,401,403 |
|
-b, –status-codes-blacklist |
Status codes to ignore: -b 404,400 (show everything except these) |
|
-l, –show-length |
Show the length of the response body. Useful for spotting interesting differences. |
|
-e, –expanded |
Print full URL (with protocol and host) instead of just the path. |
|
-r, –follow-redirect |
Follow HTTP redirects and report the final URL. |
|
-k, –no-tls-validation |
Skip TLS/SSL certificate verification. Use on self-signed cert targets. |
|
-H, –headers |
Add custom HTTP headers: -H ‘Authorization: Bearer token123’ |
|
-c, –cookies |
Add cookies: -c ‘session=abc123; role=admin’ |
|
-U, –username |
Username for Basic Auth: -U admin |
|
-P, –password |
Password for Basic Auth: -P password123 |
|
–proxy |
Route traffic through a proxy: –proxy http://127.0.0.1:8080 (Burp Suite) |
|
–timeout |
Request timeout: –timeout 10s |
|
–random-agent |
Use a random User-Agent header per request. Helps evade detection. |
|
–exclude-length |
Exclude responses with specific body length: –exclude-length 1234 |
dns Mode Flags
|
Flag |
Description |
|
-d, –domain |
Target domain: -d target.com |
|
-i, –show-ips |
Show resolved IP addresses alongside discovered subdomains. |
|
-c, –show-cname |
Show CNAME records for discovered subdomains. |
|
–wildcard |
Force continuation even when wildcard DNS is detected. |
|
–resolver |
Use a custom DNS resolver: –resolver 8.8.8.8 (Google DNS) |
vhost Mode Flags
|
Flag |
Description |
|
-u, –url |
Target URL (use IP address, not hostname): -u http://10.10.10.10 |
|
–append-domain |
Append the base domain to each wordlist entry: api → api.target.com |
|
–exclude-length |
Exclude responses matching a specific length (filter out the default vhost response) |
5. Gobuster: Real-World Command Examples
Directory & File Busting
|
# Basic directory scan gobuster dir -u https://target.com -w /usr/share/seclists/Discovery/Web-Content/common.txt # With file extensions — find .php, .html, .js, .bak files gobuster dir -u https://target.com -w common.txt -x php,html,js,txt,bak,zip # Thorough scan: medium wordlist + extensions + show lengths gobuster dir -u https://target.com \ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \ -x php,html,js,txt,bak,zip,conf \ -t 50 -l -e -o gobuster_dir.txt # Show ALL response codes except 404 (reveal 403s — often interesting) gobuster dir -u https://target.com -w common.txt -b 404 # Scan with authentication (Bearer token) gobuster dir -u https://api.target.com -w common.txt \ -H ‘Authorization: Bearer eyJhbGci…’ -x json # Scan with session cookie gobuster dir -u https://target.com/admin -w common.txt \ -c ‘session=abc123def456’ -x php # Route through Burp Suite proxy (inspect requests) gobuster dir -u https://target.com -w common.txt \ –proxy http://127.0.0.1:8080 -k # Skip TLS verification (self-signed cert) gobuster dir -u https://10.10.10.10 -w common.txt -k # Random User-Agent (basic evasion) gobuster dir -u https://target.com -w common.txt –random-agent # Rate limiting — delay between requests gobuster dir -u https://target.com -w common.txt –delay 500ms -t 5 # Quiet mode — results only, no banner gobuster dir -u https://target.com -w common.txt -q -o results.txt |
DNS Subdomain Enumeration
|
# Basic subdomain enumeration gobuster dns -d target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt # Show resolved IPs gobuster dns -d target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \ -i -t 100 # Show CNAME records too gobuster dns -d target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ -i -c # Force continue with wildcard DNS gobuster dns -d target.com -w subdomains.txt –wildcard # Use custom DNS resolver gobuster dns -d target.com -w subdomains.txt –resolver 8.8.8.8 -i |
Virtual Host (vhost) Enumeration
|
# Basic vhost enumeration (use IP, not hostname) gobuster vhost -u http://10.10.10.10 \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt # Append domain to wordlist entries (api → api.target.com) gobuster vhost -u http://10.10.10.10 \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ –append-domain # Filter out default response (exclude the common page length) # First run without filter, note the default response length, then: gobuster vhost -u http://10.10.10.10 \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ –append-domain –exclude-length 612 # With HTTPS and skip TLS verification gobuster vhost -u https://target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ –append-domain -k -t 50 |
Gobuster fuzz Mode
|
# Fuzz a URL parameter value gobuster fuzz -u ‘https://target.com/page.php?id=FUZZ’ \ -w /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt # Find hidden parameters gobuster fuzz -u ‘https://target.com/api/endpoint?FUZZ=test’ \ -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt # Fuzz with status code filter gobuster fuzz -u ‘https://target.com/FUZZ’ -w wordlist.txt \ –exclude-length 0 -b 404,400 |
|
Gobuster doesn’t do recursion — here’s the workaround Gobuster does not automatically scan discovered directories. When you find /admin, you need to run a separate scan: gobuster dir -u https://target.com/admin -w common.txt -x php. Many pentesters write a simple loop or use ffuf with -recursion instead for deeper exploration. |
6. ffuf: Core Concepts & Syntax
ffuf works on one core principle: put the word FUZZ anywhere in your request — in the URL path, query parameters, headers, cookies, POST body, or even the Host header — and ffuf replaces it with each entry from your wordlist. This makes it far more versatile than Gobuster for anything beyond simple path busting.
Basic syntax
|
ffuf -u <URL_with_FUZZ> -w <wordlist> [options] # The three things you almost always need: # -u : Target URL containing FUZZ placeholder # -w : Wordlist path # -fc : Filter out unwanted status codes (e.g., -fc 404) |
Core ffuf Flags — Complete Reference
|
Flag |
Description |
|
-u |
Target URL with FUZZ keyword: -u https://target.com/FUZZ |
|
-w |
Wordlist: -w /path/to/wordlist.txt or -w wordlist.txt:KEYWORD for named keywords |
|
-H |
Custom header (can use multiple times): -H ‘Authorization: Bearer token’ |
|
-X |
HTTP method: -X POST (default: GET) |
|
-d |
POST data body: -d ‘username=admin&password=FUZZ’ |
|
-b |
Cookie: -b ‘session=abc123; FUZZ=test’ |
|
-t |
Threads (default: 40): -t 100 for speed, -t 5 for stealth |
|
-p |
Delay between requests: -p 0.1 (100ms), -p 1 (1 second) |
|
-r |
Follow redirects |
|
-s |
Silent mode — suppress progress bar and info messages |
|
-v |
Verbose — show full URLs in output |
|
-o |
Output file: -o results.json |
|
-of |
Output format: -of json, -of csv, -of html, -of md (markdown) |
|
-k |
Skip TLS certificate verification |
|
-x |
HTTP proxy: -x http://127.0.0.1:8080 (Burp Suite) |
|
-recursion |
Enable recursive scanning of found directories |
|
-recursion-depth |
Max recursion depth: -recursion-depth 3 |
|
-e |
File extensions (comma-separated): -e php,html,js,bak |
|
-maxtime |
Stop after N seconds: -maxtime 300 |
|
-rate |
Max requests per second: -rate 100 |
|
-request |
Load a saved raw HTTP request file: -request req.txt |
|
-request-proto |
Protocol for -request mode: -request-proto https |
7. ffuf: Filters & Matchers — The Key to Useful Output
Without filters, ffuf floods you with thousands of results, most of them 404s or identical default pages. Filters and matchers are what turn raw noise into actionable findings. This is the skill that separates beginners from effective fuzzers.
Filter Flags (fc, fs, fw, fl, ft — exclude matching responses)
|
Flag |
Filters by |
Example |
|
-fc |
HTTP status code(s) |
-fc 404 or -fc 404,400,403 |
|
-fs |
Response size (bytes) |
-fs 1234 or -fs 100-200 |
|
-fw |
Word count in response |
-fw 10 (exclude responses with exactly 10 words) |
|
-fl |
Line count in response |
-fl 1 (exclude single-line responses) |
|
-ft |
Response time (ms) |
-ft 500 (exclude responses faster than 500ms) |
|
-fr |
Regex match in response body |
-fr “Not Found” (exclude responses containing this text) |
Matcher Flags (mc, ms, mw, ml, mt, mr — show only matching responses)
|
Flag |
Matches by |
Example |
|
-mc |
HTTP status code(s) |
-mc 200 or -mc 200,301,302 |
|
-ms |
Response size (bytes) |
-ms 5000 (only show responses of exactly 5000 bytes) |
|
-mw |
Word count in response |
-mw 50 (only responses with 50 words) |
|
-ml |
Line count in response |
-ml 25 |
|
-mr |
Regex match in response body |
-mr “admin|dashboard|welcome” |
|
-mt |
Response time (ms) |
-mt 5000 (only show responses taking >5 seconds — blind injection) |
How to decide which filter to use
1. Run a quick scan with no filters first, or run one request manually to see the default error response.
2. Note the size/word count of the 404 or default page. Use -fs <that_size> or -fw <that_wordcount> to filter it out.
3. If all 404s return the same 3-word response, use -fw 3. If they’re all 1234 bytes, use -fs 1234.
4. Use -mc 200,301,302 to show only clearly successful responses. Use -fc 404 to drop only 404s and show everything else (including 403s, which are often interesting).
|
403 Forbidden is NOT a dead end A 403 response means the path exists but access is restricted. Always record 403 results — they indicate sensitive functionality worth attempting to bypass. Common bypass techniques include adding a trailing slash (/admin/), modifying the HTTP method, or injecting headers like X-Original-URL: /admin. |
8. ffuf: All Fuzzing Modes with Full Commands
Directory & File Fuzzing
|
# Basic directory fuzzing ffuf -u https://target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt # Filter out 404s (essential for clean output) ffuf -u https://target.com/FUZZ -w common.txt -fc 404 # Show only 200 and redirect responses ffuf -u https://target.com/FUZZ -w common.txt -mc 200,301,302 # With file extensions ffuf -u https://target.com/FUZZ -w common.txt -e .php,.html,.js,.txt,.bak,.zip # Thorough scan with output to file ffuf -u https://target.com/FUZZ \ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \ -e .php,.html,.js,.bak,.zip,.conf \ -fc 404 -t 50 -o results.json -of json # Recursive scanning ffuf -u https://target.com/FUZZ -w common.txt -fc 404 \ -recursion -recursion-depth 3 # With Burp Suite proxy for inspection ffuf -u https://target.com/FUZZ -w common.txt -fc 404 \ -x http://127.0.0.1:8080 -k # Filter by response size (useful when 404 page has consistent size) ffuf -u https://target.com/FUZZ -w common.txt -fs 1234 # Filter by word count ffuf -u https://target.com/FUZZ -w common.txt -fw 10 |
GET Parameter Fuzzing
|
# Find hidden GET parameters (parameter name is FUZZ) ffuf -u ‘https://target.com/page.php?FUZZ=test’ \ -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \ -fs 1234 # Fuzz the value of a known parameter ffuf -u ‘https://target.com/page.php?id=FUZZ’ \ -w /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt \ -fc 404 -mc 200,500 # LFI testing — fuzz path traversal payloads ffuf -u ‘https://target.com/page.php?file=FUZZ’ \ -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt \ -fc 404 -fs 0 # IDOR testing — fuzz numeric IDs ffuf -u ‘https://target.com/api/user/FUZZ’ \ -w /usr/share/seclists/Fuzzing/Digits/1-1000.txt \ -fc 404 -mc 200 |
POST Data Fuzzing
|
# Brute-force a login form password ffuf -u https://target.com/login -X POST \ -d ‘username=admin&password=FUZZ’ \ -w /usr/share/wordlists/rockyou.txt \ -H ‘Content-Type: application/x-www-form-urlencoded’ \ -fc 401 -mc 200,302 # Username enumeration (fuzz the username field) ffuf -u https://target.com/login -X POST \ -d ‘username=FUZZ&password=Password123’ \ -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \ -H ‘Content-Type: application/x-www-form-urlencoded’ \ -fs 1234 # JSON POST body fuzzing ffuf -u https://api.target.com/login -X POST \ -d ‘{“username”:”admin”,”password”:”FUZZ”}’ \ -w /usr/share/wordlists/rockyou.txt \ -H ‘Content-Type: application/json’ \ -fc 401 # Fuzz a hidden JSON parameter name ffuf -u https://api.target.com/endpoint -X POST \ -d ‘{“FUZZ”:”test”}’ \ -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \ -H ‘Content-Type: application/json’ \ -fs 0 -mc 200 |
Subdomain Fuzzing
|
# Basic subdomain brute force ffuf -u https://FUZZ.target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \ -fc 404 -mc 200,301,302,403 # With size filter (exclude default ‘domain not found’ response) ffuf -u https://FUZZ.target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ -fs 1234 # Verbose output to see full URLs ffuf -u https://FUZZ.target.com \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ -fc 404 -v |
Virtual Host Fuzzing
|
# Fuzz the Host header to find virtual hosts # First: do a baseline request to see the default response size curl -s http://10.10.10.10 | wc -c # Then filter that size out: ffuf -u http://10.10.10.10 \ -H ‘Host: FUZZ.target.com’ \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ -fs 4242 # With HTTPS and TLS skip ffuf -u https://10.10.10.10 \ -H ‘Host: FUZZ.target.com’ \ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \ -fs 4242 -k |
Header Fuzzing
|
# Fuzz a custom header value (e.g., X-Forwarded-For bypass) ffuf -u https://target.com/admin \ -H ‘X-Forwarded-For: FUZZ’ \ -w /usr/share/seclists/Fuzzing/IPv4-Addresses.txt \ -mc 200 # Fuzz the User-Agent header ffuf -u https://target.com \ -H ‘User-Agent: FUZZ’ \ -w /usr/share/seclists/Fuzzing/User-Agents/user_agents.txt \ -fs 1234 # Fuzz header name (find interesting headers the server accepts) ffuf -u https://target.com/api/v1/users \ -H ‘FUZZ: 127.0.0.1’ \ -w /usr/share/seclists/Fuzzing/http-request-headers/http-request-headers-common.txt \ -fs 0 -mc 200 |
Cookie Fuzzing
|
# Fuzz a cookie value (e.g., role-based access control bypass) ffuf -u https://target.com/admin \ -b ‘session=abc123; role=FUZZ’ \ -w /usr/share/seclists/Fuzzing/Strings/generics.txt \ -mc 200 -fc 403 # Brute-force a session token ffuf -u https://target.com/dashboard \ -b ‘session=FUZZ’ \ -w sessions_wordlist.txt \ -mc 200 |
9. ffuf: Advanced Techniques
Multiple Wordlists (Named Keywords)
Replace FUZZ with custom keywords when you need to fuzz multiple positions simultaneously:
|
# Two-position fuzzing: username AND password (pitchfork-style) ffuf -u https://target.com/login -X POST \ -d ‘username=USER&password=PASS’ \ -w usernames.txt:USER \ -w passwords.txt:PASS \ -H ‘Content-Type: application/x-www-form-urlencoded’ \ -mode pitchfork \ -fc 401 # Cluster bomb mode (every combination — use carefully) ffuf -u https://target.com/login -X POST \ -d ‘username=USER&password=PASS’ \ -w usernames.txt:USER \ -w passwords.txt:PASS \ -H ‘Content-Type: application/x-www-form-urlencoded’ \ -mode clusterbomb \ -fc 401 # Multiple positions in URL ffuf -u ‘https://target.com/api/W1/resource/W2’ \ -w versions.txt:W1 \ -w endpoints.txt:W2 \ -mode pitchfork -fc 404 |
Using a Raw HTTP Request File
Capture a request in Burp Suite, save it, then feed it directly to ffuf — FUZZ goes anywhere in the saved request:
|
# Save request from Burp: right-click → Save item → request.txt # Place FUZZ in the saved request file where you want fuzzing to occur # Example request.txt content: # POST /login HTTP/1.1 # Host: target.com # Content-Type: application/x-www-form-urlencoded # # username=admin&password=FUZZ # Run ffuf with the saved request ffuf -request request.txt -request-proto https \ -w /usr/share/wordlists/rockyou.txt -fc 401 # Pitchfork with two placeholders in request file ffuf -request request.txt -request-proto https \ -w usernames.txt:USER -w passwords.txt:PASS \ -mode pitchfork -fc 401 |
API Fuzzing
|
# Discover API endpoints ffuf -u https://api.target.com/v1/FUZZ \ -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \ -H ‘Authorization: Bearer <token>’ \ -fc 404 -mc 200,201,400,403 # Fuzz API version ffuf -u https://api.target.com/FUZZ/users \ -w /usr/share/seclists/Discovery/Web-Content/api/api-seen-in-wild.txt \ -fc 404 # Find undocumented API routes ffuf -u https://api.target.com/api/FUZZ \ -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt \ -H ‘Content-Type: application/json’ \ -H ‘Authorization: Bearer <token>’ \ -fc 404 -t 30 |
Blind SQL Injection Detection via Response Time
|
# Use -mt to find parameters causing time delays (blind SQLi) ffuf -u ‘https://target.com/search.php?q=FUZZ’ \ -w /usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt \ -fc 404 \ -mt 5000 # -mt 5000 = only show responses that take >5000ms (5 seconds) # A time delay suggests time-based blind SQL injection |
10. Gobuster vs ffuf: Side-by-Side Comparison
Here’s when to reach for each tool during a real engagement:
|
Task |
Best tool |
Why |
|
Quick directory bust on a new target |
Gobuster |
Less to type, fast, simple output |
|
DNS subdomain enumeration |
Gobuster dns |
Better DNS-specific options (-i, -c, –resolver) |
|
Virtual host discovery |
Either |
Both work well; ffuf’s -fs filter is easier to calibrate |
|
POST form login brute force |
ffuf |
Gobuster can’t fuzz POST bodies; ffuf handles this natively |
|
GET parameter discovery |
ffuf |
FUZZ can be placed in the parameter name or value position |
|
API endpoint fuzzing |
ffuf |
Better header control, JSON body support, named keywords |
|
Recursive directory scanning |
ffuf |
Gobuster has no recursion; ffuf -recursion handles it |
|
Cookie or header fuzzing |
ffuf |
ffuf can place FUZZ in any header or cookie value |
|
Blind injection timing attacks |
ffuf |
-mt flag detects time-delayed responses |
|
Piping output for scripting |
Gobuster -q |
Cleaner bare output; ffuf JSON is richer but needs parsing |
|
Multi-position fuzzing (pitchfork) |
ffuf |
Named keywords + -mode pitchfork/clusterbomb |
|
Filtering false positives precisely |
ffuf |
fc/fs/fw/fl/fr/ft give much finer control than Gobuster |
Other tools worth knowing
|
Tool |
Standout feature |
Install |
|
Feroxbuster |
Recursive scanning with Rust speed. Best for deep recursive enumeration. |
cargo install feroxbuster |
|
Dirsearch |
Python-based, great default config, built-in extension handling. |
pip install dirsearch |
|
wfuzz |
Older Python fuzzer, powerful filter system, good for learning. |
pip install wfuzz |
|
dirb |
Pre-installed on Kali, simple, good for beginners. Very slow. |
sudo apt install dirb |
11. The Web Enumeration Workflow: Where These Tools Fit
Directory and parameter fuzzing has a specific place in the web application pentest methodology. Using it at the right time — and in the right order — is what makes the difference between finding nothing and finding everything.
Phase 1: Passive recon (before you fuzz)
• Browse the application manually with Burp Suite’s proxy running. Let the site map build organically. See the Burp Suite Cheat Sheet on hackingloops.com for the full setup guide.
• Note all technologies visible in headers (X-Powered-By, Server), response bodies, and source comments.
• Check robots.txt and sitemap.xml for hidden paths the site itself advertises.
• View page source for commented-out links, API endpoints, JavaScript file references.
Phase 2: Initial directory sweep (Gobuster first)
• Run Gobuster with common.txt and common extensions. This takes seconds and catches 70% of findings.
• Review all 301/302 redirects — follow them manually.
• Record all 403 responses — these indicate protected but existing resources.
• Note all interesting directories for deeper scanning in Phase 3.
Phase 3: Deep enumeration (ffuf for precision)
• Run ffuf on discovered directories with larger wordlists and recursive scanning.
• Fuzz GET parameters on interesting pages: ffuf -u ‘https://target.com/page.php?FUZZ=test’ -w burp-parameter-names.txt -fs 1234.
• Enumerate subdomains and virtual hosts if the target scope includes them.
• Test API endpoints discovered from Burp’s JS Link Finder extension.
Phase 4: Targeted fuzzing (exploitation support)
• Found a login form? Use ffuf to brute force or enumerate usernames.
• Found a file upload endpoint? Fuzz file extensions to find accepted types.
• Found an ID parameter? Fuzz numeric values to test for IDOR.
• Found an interesting parameter? Fuzz the value with injection payload lists.
• Pass anything that needs deeper testing to Burp Suite Repeater for manual analysis. See the Burp Suite Cheat Sheet →
• For any SQL injection candidates found, pass to SQLmap. See the SQLmap Cheat Sheet →
12. Common Mistakes & Pro Tips
Mistakes That Cost Time
Mistake 1: Not using extensions in dir mode
Running gobuster dir without -x php,html,js,bak will completely miss files. A hidden admin panel called /admin/login.php won’t appear if you’re only looking for directories. Always add extensions for web targets.
Mistake 2: Not filtering ffuf output
Running ffuf without any -fc or -fs filter gives you thousands of results — most useless. Always do a baseline request first, note the default error response size, then filter it out with -fs. If you don’t know what to filter, start with -fc 404 at minimum.
Mistake 3: Using too many threads on a production target
Running 100 threads against a small production server can crash it or trigger alerts. For targets with rate limiting or WAFs, use -t 10 and –delay 200ms. Save the high thread counts for CTF lab machines.
Mistake 4: Stopping at 404
Many web apps return 200 for everything — even non-existent pages — with a custom error message. A 200 response doesn’t mean you found something. Check the response size and content, not just the status code. Use -fs to filter responses of the same size as the error page.
Mistake 5: Missing the /api/ prefix
Modern web apps often have their API under /api/v1/ or /api/v2/ — sometimes both. Always run a separate scan with the API-specific wordlists from SecLists: /usr/share/seclists/Discovery/Web-Content/api/
Pro Tips
Tip 1: Always check 403 responses
Filter to show 403s alongside 200s with gobuster dir -b 404 or ffuf -mc 200,301,302,403. Found /admin returning 403? Try: appending a trailing slash (/admin/), using a different HTTP method, adding X-Forwarded-For: 127.0.0.1 header, or trying /ADMIN, /%2fadmin, or /./admin/.
Tip 2: Fuzz after finding each new directory
Gobuster doesn’t recurse. When you find /backup, immediately run: gobuster dir -u https://target.com/backup -w common.txt -x php,zip,bak. Or use ffuf with -recursion so it handles this automatically.
Tip 3: Use the -e flag wisely — backup and config files are goldmines
Always include .bak, .old, .zip, .tar.gz, .swp, .config, .conf, .env in your extension list. Developers often leave backup copies of configuration files — .env files especially can contain database credentials, API keys, and secret tokens.
Tip 4: Use -o to save output, always
Fuzzing output scrolls fast and you’ll miss results. Save everything with -o output.txt (Gobuster) or -o output.json -of json (ffuf). JSON output from ffuf is especially useful as it records every request’s status, size, and words for later analysis.
Tip 5: Slow down against WAF-protected targets
If a target has a Web Application Firewall, fast fuzzing will get you blocked instantly. Use -t 5 –delay 500ms (Gobuster) or -t 5 -p 0.5 -rate 10 (ffuf) to stay under the radar. Also try –random-agent to rotate User-Agent strings.
Tip 6: Combine tools in sequence
The best recon workflow is: Gobuster for the quick first sweep → ffuf for deep parameter and post-body fuzzing → Burp Suite for manual analysis of interesting findings → SQLmap or other exploit tools where injection is suspected. Each tool in the chain narrows the attack surface for the next.
13. Quick Reference Summary
The condensed version for bookmarking.
Gobuster quick commands
|
Task |
Command |
|
Basic dir scan |
gobuster dir -u https://target.com -w common.txt |
|
Dir scan + extensions |
gobuster dir -u https://target.com -w common.txt -x php,html,js,bak |
|
Show all except 404 |
gobuster dir -u https://target.com -w common.txt -b 404 |
|
DNS subdomain enum |
gobuster dns -d target.com -w subdomains-top1million-20000.txt -i |
|
Vhost discovery |
gobuster vhost -u http://10.10.10.10 -w subdomains-top1million-5000.txt –append-domain |
|
With auth header |
gobuster dir -u https://target.com -w common.txt -H ‘Authorization: Bearer TOKEN’ |
|
With cookie |
gobuster dir -u https://target.com/admin -w common.txt -c ‘session=abc123’ |
|
Via Burp proxy |
gobuster dir -u https://target.com -w common.txt –proxy http://127.0.0.1:8080 -k |
ffuf quick commands
|
Task |
Command |
|
Basic dir fuzzing |
ffuf -u https://target.com/FUZZ -w common.txt -fc 404 |
|
Dir + extensions |
ffuf -u https://target.com/FUZZ -w common.txt -e .php,.html,.bak -fc 404 |
|
Recursive scan |
ffuf -u https://target.com/FUZZ -w common.txt -fc 404 -recursion -recursion-depth 3 |
|
GET param discovery |
ffuf -u ‘https://target.com/page.php?FUZZ=test’ -w burp-parameter-names.txt -fs 1234 |
|
POST login brute force |
ffuf -u https://target.com/login -X POST -d ‘user=admin&pass=FUZZ’ -w rockyou.txt -fc 401 |
|
Vhost fuzzing |
ffuf -u http://10.10.10.10 -H ‘Host: FUZZ.target.com’ -w subdomains.txt -fs 4242 |
|
Subdomain fuzzing |
ffuf -u https://FUZZ.target.com -w subdomains-top1million-5000.txt -fc 404 |
|
Pitchfork (user+pass) |
ffuf -u https://target.com/login -X POST -d ‘user=USER&pass=PASS’ -w u.txt:USER -w p.txt:PASS -mode pitchfork -fc 401 |
|
Raw request file |
ffuf -request request.txt -request-proto https -w wordlist.txt -fc 404 |
|
Save JSON output |
ffuf -u https://target.com/FUZZ -w common.txt -fc 404 -o results.json -of json |
Essential wordlist paths (Kali Linux)
|
Use case |
Path |
|
Quick dir bust |
/usr/share/seclists/Discovery/Web-Content/common.txt |
|
Thorough dir bust |
/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt |
|
Large dir/files |
/usr/share/seclists/Discovery/Web-Content/raft-large-files.txt |
|
API endpoints |
/usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt |
|
Subdomains (fast) |
/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt |
|
Subdomains (thorough) |
/usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt |
|
Parameter names |
/usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt |
|
Password brute force |
/usr/share/wordlists/rockyou.txt |
|
What to learn next These tools complete the web app hacking recon and fuzzing phase: • Burp Suite Cheat Sheet — intercept and manually analyse everything your fuzzing discovers. Internal link → • SQLmap Cheat Sheet — when fuzzing finds SQLi candidates, SQLmap does the exploitation. Internal link → • Nikto Cheat Sheet — complement directory busting with web server vulnerability scanning. Internal link → |
hackingloops.com · Updated April 2026 · For authorized testing only