Tools · Attack surface inventory · 06 / 07
ffuf on your own staging site: find content the route list forgot
Use ffuf with a common wordlist, auto-calibration, and a low request rate to find files and folders on a staging host that are missing from the application’s route inventory.
Why a defender fuzzes paths
Applications collect stray files: an old admin folder, a backup archive, a debug page left by a contractor. None of them appear in the route table the developers maintain. Requesting common names from a wordlist finds them before someone else does.
Content discovery sends thousands of requests, so it belongs on staging or on production only with the owner’s written approval and a rate they agreed to.
A calibrated run
FUZZ marks the spot ffuf replaces with each word. -ac auto-calibrates by requesting random paths first and filtering responses that look like the site’s generic “not found” page, which matters for applications that answer 200 to everything. -rate caps requests per second.
ffuf -u https://staging.hackblue-lab.org/FUZZ \ -w /usr/share/seclists/Discovery/Web-Content/common.txt \ -ac -rate 15 -t 5 \ -mc 200,204,301,302,307,401,403 \ -o ffuf.json -of json
Reading the matches
Each hit shows status, size, words, and lines. Hits with the same size usually share a template; a different size is worth opening.
admin [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 14ms] api [Status: 401, Size: 52, Words: 3, Lines: 1, Duration: 22ms] backup [Status: 403, Size: 162, Words: 4, Lines: 8, Duration: 11ms] server-status [Status: 200, Size: 4821, Words: 310, Lines: 96, Duration: 19ms] jq -r '.results[] | [.status, .length, .url] | @tsv' ffuf.json
Worked case: compare with the route table
The developers export their framework routes. admin and api are on it. backup and server-status are not. backup returns 403, which still confirms the folder exists; the deploy log shows a nightly archive job writing there. server-status is Apache’s status module, readable from anywhere, and lists client addresses and URLs in real time.
The fixes are configuration, not code: move the archive outside the web root, and restrict server-status to localhost with a Require local rule.
<Location "/server-status">
SetHandler server-status
Require local
</Location>Diagram
Content discovery against a route list
- Calibrate
Learn what the site’s not-found page looks like.
-ac
- Request
Try each word at a polite rate.
ffuf -u https://staging.hackblue-lab.org/FUZZ -w common.txt -rate 15
- Compare
Subtract the known routes.
comm -13 routes.txt <(jq -r '.results[].input.FUZZ' ffuf.json | sort)
- Close
Move or restrict what should not be public.
Require local
Check yourself
1. The site answers 200 to every path. Which ffuf option helps most?
2. backup returns 403. What does that tell you?
3. Where should a defender run broad content discovery first?