HackBlue

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.

11 min read · practice only with authorization

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.

Snippet
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.

Snippet
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.

Snippet
<Location "/server-status">
    SetHandler server-status
    Require local
</Location>

Diagram

Content discovery against a route list

  1. Calibrate

    Learn what the site’s not-found page looks like.

    Flag
    -ac
  2. Request

    Try each word at a polite rate.

    Command
    ffuf -u https://staging.hackblue-lab.org/FUZZ -w common.txt -rate 15
  3. Compare

    Subtract the known routes.

    Command
    comm -13 routes.txt <(jq -r '.results[].input.FUZZ' ffuf.json | sort)
  4. Close

    Move or restrict what should not be public.

    Config
    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?