🛡️ Methodology Checklist
- VHost fuzzing:
ffuf -u http://[TARGET_IP] -H "Host: FUZZ.[DOMAIN]" -w [WORDLIST] -fs [DEFAULT_SIZE] - Subdomain fuzzing:
ffuf -u http://FUZZ.[DOMAIN] -w [WORDLIST] - GET parameter fuzzing:
ffuf -u http://[TARGET]/page?FUZZ=value -w [WORDLIST] - POST parameter fuzzing:
ffuf -u http://[TARGET]/page -X POST -d "FUZZ=value" -H "Content-Type: application/x-www-form-urlencoded" -w [WORDLIST] - Value fuzzing:
ffuf -u http://[TARGET]/page?id=FUZZ -w ids.txt - Filter responses: use
-fc,-fs,-fw,-flto reduce noise
🎯 Operational Context
Use when: Discovering hidden vhosts via Host header fuzzing or unknown GET/POST parameters via parameter fuzzing.
Think Dumber First: ffuf -u http://[TARGET_IP]/ -H 'Host: FUZZ.target.htb' -w subdomains.txt -fs [default_size] for vhost. For params: ffuf -u http://[TARGET]/page.php?FUZZ=value -w parameters.txt -mc 200. Both take minutes and find what manual browsing misses.
Skip when: Known complete list of vhosts and parameters from source code review — skip brute force.
⚡ Tactical Cheatsheet
| Command | Tactical Outcome |
|---|---|
ffuf -w subdomains-top1million-5000.txt:FUZZ -u https://FUZZ.[DOMAIN]/ | Public subdomain DNS fuzzing |
ffuf -w subdomains-top1million-5000.txt:FUZZ -u http://[TARGET_IP]:[PORT]/ -H 'Host: FUZZ.[DOMAIN]' | VHost fuzzing — inject into Host header |
ffuf -w subdomains-top1million-5000.txt:FUZZ -u http://[TARGET_IP]:[PORT]/ -H 'Host: FUZZ.[DOMAIN]' -fs [BASELINE_SIZE] | VHost fuzz with false-positive filter |
sudo sh -c 'echo "[TARGET_IP] admin.[DOMAIN]" >> /etc/hosts' | Add discovered VHost to local routing |
ffuf -w burp-parameter-names.txt:FUZZ -u http://[TARGET_IP]:[PORT]/admin.php?FUZZ=key -fs [BASELINE_SIZE] | GET parameter name discovery |
ffuf -w burp-parameter-names.txt:FUZZ -u http://[TARGET_IP]:[PORT]/admin.php -X POST -d 'FUZZ=key' -H 'Content-Type: application/x-www-form-urlencoded' -fs [BASELINE_SIZE] | POST parameter name discovery |
curl http://[TARGET_IP]:[PORT]/admin.php -X POST -d 'id=key' -H 'Content-Type: application/x-www-form-urlencoded' | Verify discovered POST parameter with curl |
for i in $(seq 1 1000); do echo $i >> ids.txt; done | Generate sequential numeric wordlist for value fuzzing |
ffuf -w ids.txt:FUZZ -u http://[TARGET_IP]:[PORT]/admin.php -X POST -d 'id=FUZZ' -H 'Content-Type: application/x-www-form-urlencoded' -fs [BASELINE_SIZE] | Value fuzz discovered parameter |
-fc [CODE] | Filter by HTTP status code (e.g., -fc 403) |
-fs [SIZE] | Filter by response size |
-fw [COUNT] | Filter by word count |
-fl [LINES] | Filter by line count |
🔬 Deep Dive & Workflow
Subdomain vs VHost
| Method | Uses DNS | Use Case |
|---|---|---|
Subdomain fuzzing (FUZZ.domain.com) | Yes — public DNS | Public sites on different IPs |
VHost fuzzing (-H 'Host: FUZZ.domain') | No — sends to known IP | Internal/private sites on same IP |
If errors count = total requests → DNS resolution failed → switch to VHost fuzzing.
VHost Fuzzing Workflow
# Step 1: Run without filter (every result = 200 OK from fallback page)
ffuf -w subdomains.txt:FUZZ \
-u http://[TARGET_IP]:[PORT]/ \
-H 'Host: FUZZ.[DOMAIN]'
# Step 2: Note the baseline Size (e.g., 900)
# Step 3: Re-run with filter
ffuf -w subdomains.txt:FUZZ \
-u http://[TARGET_IP]:[PORT]/ \
-H 'Host: FUZZ.[DOMAIN]' \
-fs 900
# Step 4: Add found VHost to /etc/hosts
sudo sh -c 'echo "[TARGET_IP] admin.[DOMAIN]" >> /etc/hosts'Multiple sizes: -fs 900,322
Parameter Fuzzing
# GET
ffuf -w burp-parameter-names.txt:FUZZ \
-u http://admin.[DOMAIN]:[PORT]/admin.php?FUZZ=key \
-fs [BASELINE_SIZE]
# POST (requires Content-Type header for PHP backends)
ffuf -w burp-parameter-names.txt:FUZZ \
-u http://admin.[DOMAIN]:[PORT]/admin.php \
-X POST -d 'FUZZ=key' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-fs [BASELINE_SIZE]“This method is deprecated” response = param name is correct, try different value or POST.
Value Fuzzing
# Generate numeric IDs
for i in $(seq 1 1000); do echo $i >> ids.txt; done
# Fuzz values
ffuf -w ids.txt:FUZZ \
-u http://[TARGET_IP]:[PORT]/admin.php \
-X POST -d 'id=FUZZ' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-fs [BASELINE_SIZE]
# Confirm with curl
curl -X POST http://[TARGET_IP]:[PORT]/admin.php \
-d 'id=[VALID_VALUE]' \
-H 'Content-Type: application/x-www-form-urlencoded'Filtering Reference
| Flag | Filters on |
|---|---|
-fc 403 | HTTP status code |
-fs 900 | Response byte size |
-fw 423 | Word count |
-fl 56 | Line count |
🛠️ Troubleshooting & Edge Cases
| Problem | Cause | Fix |
|---|---|---|
| Vhost fuzz returns all same size | Catch-all vhost | Filter by size: add -fs [default_response_size]; test baseline first with invalid vhost |
| Parameter fuzz returns too many 200s | Application returns 200 for all params | Filter by response size or content: -fs [size] or -fr 'not found' |
| Vhost fuzzing misses internal names | Wordlist lacks internal naming patterns | Add company-specific prefixes to wordlist: dev-, staging-, api-, admin-, int- |
| POST parameter fuzzing format wrong | ffuf body vs query | For POST params: -X POST -d 'FUZZ=test' -H 'Content-Type: application/x-www-form-urlencoded' |
| Rate limiting blocks ffuf | Target rate limits aggressive scanning | Add -rate 100 and -p 0.1 (100ms delay) to slow scan |
📝 Reporting Trigger
Finding Title: Hidden Virtual Hosts and Parameters Discovered via Fuzzing Impact: Undiscovered virtual hosts and hidden HTTP parameters expose unprotected application endpoints, admin panels, and debug functionality not accessible through normal application flow. Root Cause: No comprehensive endpoint inventory. Internal virtual hosts rely on DNS obscurity rather than authentication controls. Recommendation: Document and inventory all virtual hosts and API parameters. Apply authentication and authorization to all discovered endpoints. Remove debug parameters from production. Implement API gateway with explicit parameter allowlisting.