Back to Blog

Attacking Web Applications With Ffuf - HTB Academy

Published: December 15, 2025

Last Updated: December 17, 2025

Download Ffuf Cheatsheet here

Ffuf is used for web fuzzing/directory brute-forcing

  • fuzzing for directories
  • fuzzing for files and extensions
  • identifying hidden vhosts
  • fuzzing for PHP parameters
  • fuzzing for parameter values

Basically, we send bulk requests to the webserver and check for various response codes to determine if a page exists and/or whether a parameter/value is valid.

Wordlists: SecLists

Directory Fuzzing

đź’ˇ Tip for locating files
locate directory-list-2.3-small.txt

Taking a look at this wordlist we will notice that it contains copyright comments at the beginning, which can be considered as part of the wordlist and clutter the results. We can use the following in ffuf to get rid of these lines with the -ic flag.

  • -w for wordlist
  • -u for url
  • Assign a wordlist to the keyword FUZZ to refer it to where we want to fuzz.
ffuf -w /opt/useful/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://SERVER_IP:PORT/FUZZ

We can also increase the number of threads with -t 200

Extension Fuzzing

Common file almost always found in any website: index.* If the wordlist already contains a dot (.), don’t add the dot after “index” in the fuzzing command.

ffuf -w /opt/useful/seclists/Discovery/Web-Content/web-extensions.txt:FUZZ -u http://SERVER_IP:PORT/blog/indexFUZZ

Recursive Fuzzing

To start fuzzing for directories within directories, we can automatically start another scan under any newly identified directory.

-recursion to enable recursive scanning -reursion-depth to specify recursion depth -e to specify extension -v to output full URLs so it’s easier to tell which file is under which directory

ffuf -w /opt/useful/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://SERVER_IP:PORT/FUZZ -recursion -recursion-depth 1 -e .php -v

DNS Records

Browsers map URL to an IP by looking into the local /etc/hosts file and the DNS.

To connect to a private website (one that cannot be found in the public DNS) like academy.htb we add it to our /etc/hosts file.

sudo sh -c 'echo "SERVER_IP  academy.htb" >> /etc/hosts'

Sub-domain Fuzzing

A sub-domain is any website underlying another domain.

eg. https://academy.hackthebox.com is the academy sub-domain of hackthebox.com

ffuf -w /opt/useful/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u https://FUZZ.inlanefreight.com/

If we run the above on academy.htb, which is a private domain, we will not get any hits back. This means that there are no public sub-domains under academy.htb because it does not have a public DNS record.

Vhost Fuzzing

Allows us to fuzz non-public sub-domains by using HTTP headers

Vhost is basically a sub-domain served on the same server and has the same IP, such that a single IP could be serving two or more different websites

-H to specify a header

ffuf -w /opt/useful/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://academy.htb:PORT/ -H 'Host: FUZZ.academy.htb'

If the Vhost exists, we should get a different response size.

Filtering Results

ffuf -h

...SNIP...
MATCHER OPTIONS:
  -mc              Match HTTP status codes, or "all" for everything. (default: 200,204,301,302,307,401,403)
  -ml              Match amount of lines in response
  -mr              Match regexp
  -ms              Match HTTP response size
  -mw              Match amount of words in response

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
  -fr              Filter regexp
  -fs              Filter HTTP response size. Comma separated list of sizes and ranges
  -fw              Filter by amount of words in response. Comma separated list of word counts and ranges
<...SNIP...>

If we know the response size of the incorrect results is, say, 900, we can filter it out using -fs 900.

ffuf -w /opt/useful/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://academy.htb:PORT/ -H 'Host: FUZZ.academy.htb' -fs 900

Parameter Fuzzing - GET

GET requests are usually passed right after the URL, with a ? symbol

ffuf -w /opt/useful/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://admin.academy.htb:PORT/admin/admin.php?FUZZ=key -fs xxx
  1. fuzz for subdomains
  2. add found subdomains to /etc/hosts
  3. fuzz subdomains recursively to find possible extensions
  4. parameter fuzzing on the results of step 3

Parameter Fuzzing - POST

POST requests are not passed with the URL and cannot simply be appended after a ? symbol

In PHP, POST data content-type can only accept application/x-www-form-urlencoded

ffuf -w /opt/useful/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://admin.academy.htb:PORT/admin/admin.php -X POST -d 'FUZZ=key' -H 'Content-Type: application/x-www-form-urlencoded' -fs xxx
curl http://admin.academy.htb:PORT/admin/admin.php -X POST -d 'id=key' -H 'Content-Type: application/x-www-form-urlencoded'

Value Fuzzing

for i in $(seq 1 1000); do echo $i >> ids.txt; done
ffuf -w ids.txt:FUZZ -u http://admin.academy.htb:PORT/admin/admin.php -X POST -d 'id=FUZZ' -H 'Content-Type: application/x-www-form-urlencoded' -fs xxx

Skills Assessment - Web Fuzzing

Commands I ran in order:

  1. fuzz subdomains
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -H "Host: FUZZ.academy.htb" -u http://94.237.50.128:43758/ -fs 985

→ test, archive, faculty

  1. add all of these to /etc/hosts
  2. extension fuzzing
ffuf -w /usr/share/seclists/Discovery/Web-Content/web-extensions.txt:FUZZ -u http://archive.academy.htb:43758/indexFUZZ

→ repeat for all the subdomains found

  1. start page fuzzing
ffuf -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://faculty.academy.htb:43758/FUZZ -recursion -recursion-depth 1 -e .php,.phps,.php7 -v -ic -mr "You don't have access"

→ repeat for all the subdomains found

  1. Only prints the output if the page contains “HTB”
ffuf -w /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt:FUZZ -u http://faculty.academy.htb:51841/courses/linux-security.php7 -X POST -d "username=FUZZ" -H "Content-Type: application/x-www-form-urlencoded" -fs 781 -mr "HTB"
  1. curl to get flag
curl http://faculty.academy.htb:51841/courses/linux-security.php7 -X POST -d 'username=harry' -H 'Content-Type: application/x-www-form-urlencoded'