Find Hidden Web Directories - Fuzz URLs with ffuf
Web servers often have secret directories, not linked from anywhere.
You could find them by trying different paths manually: /secret, /.svn /admin. This article shows you how fuff can do this to you automatically.
For practice, I coded a target that you can run locally, without Internet. I will also tell you the solution, so you can test your environment. As bonus, there is a challenge target where you can find to solution yourself.
What the Fuff?
Fuff is a web fuzzer by joohoi. This article shows you how you can use it to find hidden directories, just like gobuster or dirbuster.
Fuff is a full featured fuzzing tool. This article just fuzzes hidden directories, but you can also use fuff to fuzz anything: headers, POST parameters...
Use of penetration testing techniques requires legal and ethical considerations. To safely use these tools, tactics and procedures, you might need to obtain contracts and permissions; and posses adequate technical skills. Check your local laws.
Fuff is very fast. Disconnect your internet and play locally to avoid leaking packets to the Internet.
This tutorial was tested on Debian Linux amd64. It probably works on other Linuxes, too.
Download a sample target
Here is a sample target I wrote for you: dirfuzt-0. It has a secret page, not linked from anywhere from the site. Download it and run it
$ wget https://terokarvinen.com/2023/fuzz-urls-find-hidden-directories/dirfuzt-0 $ chmod u+x dirfuzt-0 $ ./dirfuzt-0 Learn more at TeroKarvinen.com http://127.0.0.2:8000
Now you can use your browser, like Firefox, to browse the site (use the URL dirfuzt prints you)
Does it say "Nothing, nil, null, nada."? Well, now you have your practice target running.
As long as the server is running, it will not give you the prompt back. You can use shell from another window.
Let's try our luck! Maybe it's http://127.0.0.2:8000/secret ? Nope.
We could keep trying. Or we could let ffuf try a huge number of URLs for us, automatically.
Install ffuf, a fast web fuzzer / dir buster
Download and extract a release of ffuf.
$ wget https://github.com/ffuf/ffuf/releases/download/v2.0.0/ffuf_2.0.0_linux_amd64.tar.gz $ tar -xf ffuf_2.0.0_linux_amd64.tar.gz $ ./ffuf Fuzz Faster U Fool - v2.0.0 ...
Well done, now you've got ffuf installed.
In case the link ever goes stale, here is a local mirror of ffuf_2.0.0_linux_amd64.tar.gz.
Install a Dictionary of Common Web Paths
We'll still need a dictionary. For directories, a text file with possible directories, one per line. You could even write one yourself:
secret/ .svn/ dashboard/
But luckily, many such dictionaries already exist. We can use one from Seclists by Daniel Miessler and others.
$ wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/common.txt
In case it ever disappears, here is a local mirror of SecLists common.txt It's just one path after another, just short of five thousand paths total.
$ head -3 common.txt .bash_history .bashrc .cache $ wc -l common.txt 4715 common.txt
Fuzz Faster, You F^H^H^Hool!
Fuff is very fast. Now might be a good time to disconnect your Internet before you start generating a lot of requests.
You can see all ffuf parameters with
It prints to stderr, so we need a funny pipe to see it paginated (space and b move, q quits)
$ ./ffuf |& less
Let's try the obvious approach, wordlist -w and target url -u
$ ./ffuf -w common.txt -u http://127.0.0.2:8000/FUZZ
Try every line in common.txt in place of FUZZ. So fuff will request
and so on.
Wow, that was fast! Did it already do almost 5k requests? Let's look at the output
/'___\ /'___\ /'___\ /\ \__/ /\ \__/ __ __ /\ \__/ \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\ \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/ \ \_\ \ \_\ \ \____/ \ \_\ \/_/ \/_/ \/___/ \/_/ v2.0.0 ________________________________________________ :: Method : GET :: URL : http://127.0.0.2:8000/FUZZ :: Wordlist : FUZZ: /home/vagrant/common.txt :: Follow redirects : false :: Calibration : false :: Timeout : 10 :: Threads : 40 :: Matcher : Response status: 200,204,301,302,307,401,403,405,500 ________________________________________________ [Status: 200, Size: 132, Words: 6, Lines: 10, Duration: 1ms] * FUZZ: .web [Status: 200, Size: 132, Words: 6, Lines: 10, Duration: 1ms] * FUZZ: .cache [Status: 200, Size: 132, Words: 6, Lines: 10, Duration: 1ms] * FUZZ: .bashrc ... and thousands more ...
And it goes on and on - thousands of responses are listed.
Everything is OK
The stupid web server is giving us HTTP status 200 OK for everything. But if we look at the pages, they just say "Nothing, nil, null, nada.". Even ones with interesting URLs, like http://127.0.0.2:8000/.bashrc.
When this happens, we must look at other common qualities of unwanted responses. And filter them out.
Filter options are listed in ffuf help
$ ./fuff |& less FILTER OPTIONS: -fc Filter HTTP status codes from response. Comma separated list of codes and ranges -fl Filter by amount of lines in response. Comma separated list of line counts and ranges -fmode Filter set operator. Either of: and, or (default: or) -fr Filter regexp -fs Filter HTTP response size. Comma separated list of sizes and ranges -ft Filter by number of milliseconds to the first response byte, either greater or less than. EG: >100 or <10 -fw Filter by amount of words in response. Comma separated list of word counts and ranges
Looking at a sample of 10-20 responses, we can see that most have a lot in common:
[Status: 200, Size: 132, Words: 6, Lines: 10, Duration: 1ms] [Status: 200, Size: 132, Words: 6, Lines: 10, Duration: 1ms] [Status: 200, Size: 132, Words: 6, Lines: 10, Duration: 1ms] ...
The unwanted hits, false positives have the same:
- (HTTP) Status (-fc). But the hidden pages are probably 200 OK, too.
- Size (in bytes) (-fs)
- Words (-fw)
- Lines (-fl)
- Duration (in milliseconds) (-ft). Would not be my fist choice, as it can vary by chance.
The size of each unwanted response seems to be 132 bytes. That's 132 ASCII characters. It's shorter than an SMS text message! Let's filter by that.
$ ./ffuf -w common.txt -u http://127.0.0.2:8000/FUZZ -fs 132
Just two matched responses:
[Status: 200, Size: 160, Words: 10, Lines: 11, Duration: 0ms] * FUZZ: admin [Status: 301, Size: 64, Words: 3, Lines: 3, Duration: 2ms] * FUZZ: render/https://www.google.com
Jackpot? Let's test with a browser (and maybe curl)
Manual verification confirms that /admin is the URL we were looking for. As the page says: "You've found it!".
The other one is a strange redirector, accepting many URLs after "/render/https://".
Well done, you've just fuzzed a hidden directory.
Your turn - Challenge
Can you find two URLs:
- Admin page
- Version control related page
Challenge binary dirfuzt-1.
Notice that this is a different binary from dirfuzt-0. You must shut the first exercise down before you can hack the second one. The challenge binary frontpage has the word "dirfutz-1" in the title.
Keep it safe, legal and ethical - use your powers for good.
See Joona 'joohoi' Hoikkala himself teach ffuf in HelSec:
Try ffuf on some practice target you're working with.
You just fuzzed some directory paths. Try fuzzing something else, like POST requests, query string parameters or request headers.
Fuff homepage https://github.com/ffuf/ffuf
Miessler, Haddix, g0tmi1k: SecLists https://github.com/danielmiessler/SecLists
2023-11-06: fixed a typo.