Harnessing the power of wfuzz for web hacking

In today’s post, I’ll introduce you to a tool that should be a part of every bug hunter’s toolkit, wfuzz! I use wfuzz in every bug bounty program I participate in. If you don’t know what wfuzz is, it’s a web application fuzzer. And if you haven’t heard of a web application fuzzer, they’re a type of tool that automates web requests.

As you’ll see in this post, fuzzers are a simple yet extremely powerful tool and by the end of this reading you’ll be able to confidently use wfuzz, one of the best in the game!

Practical Examples

Instead of teaching you the syntax, I’m going to run you through a series of hypothetical, real-world examples so you can use it in your next pentest or bug hunt.

For simplicity, I’m going to use a popular repository of wordlists called SecLists. These wordlists were put together by a few well-known security professionals including Daniel Miessler and Jason Haddix. I highly recommend you check out the repo and get familiar with what’s in some of the lists.

Directory Discovery

Discovering hidden files or directories of a web application can be a gold mine for security testers. wfuzz makes this a snap by fuzzing the target url:

wfuzz -c -w raft-small-directories-lowercase.txt -u "https://example.com/FUZZ"

Let’s break this down:

  • -c, colored output to make output easier to read
  • -w, the specified wordlist
  • -u, the url to fuzz

You might have noticed the word FUZZ in the URL. This is the keyword that tells wfuzz where to fuzz, or supply all the lines from the wordlist.

In this example, the output would look something like this:

* Wfuzz 2.4.5 - The Web Fuzzer                         *

Target: https://example.com/FUZZ
Total requests: 20116

ID           Response   Lines    Word     Chars       Payload

000000007:   404        0 L      0 W      0 Ch        "cache"
000000008:   200        0 L      0 W      0 Ch        "media"
000000009:   404        0 L      0 W      0 Ch        "js"
000000001:   200        0 L      0 W      0 Ch        "cgi-bin"
000000002:   404        0 L      0 W      0 Ch        "images"

As you can see, wfuzz neatly prints out the response code, payload used, as well as the number of lines, words, and characters in the response.

To make the output a little cleaner, I can filter it based on any of the response attributes, like status code:

$ wfuzz -c -w raft-small-directories-lowercase.txt -u "https://example.com/FUZZ" --sc 200


000000008:   200        0 L      0 W      0 Ch        "media"
000000001:   200        0 L      0 W      0 Ch        "cgi-bin"

Now all that is shown are responses with status code 200. We can also use use --/sl/sw/sh/ss<number> for only showing responses with a specific number of lines, words, characters or that match a specific regex respectively.

Alternatively, you can replace --s with --h to hide matches rather than showing them.

This one-liner can lead to some big finds, including configuration files, admin logins, and much more depending on the wordlist.

Wordlist Contexts

A little bit of recon with a tool like wappalyzer can go a long way. Knowing what Content Management System (think WordPress or Drupal), API endpoint locations, etc. can result in more findings.

For example, if I knew my target was running on top of an Nginx server, I might use a wordlist catered towards default files and directories:

wfuzz -c -w nginx.txt -u "https://example.com/FUZZ" --sc 200,403

If you uncovered an API endpoint, you can use a wordlist of common object names (like user, team, admin, etc.):

wfuzz -c -w /api/objects.txt -u "https://api.example.com/v2/FUZZ" --hl 4037

Using a wordlist that is right for the situation makes it more likely that you’ll find something interesting. Don’t just blindly use random wordlists and there’s no one wordlist to rule them all!

Subdomain Bruteforcing

Finding subdomains is key to expanding your attack surface. More often than not, the most interesting subdomains aren’t found passively.

wfuzz can fuzz anywhere the FUZZ keyword is located in a request, including in headers.

To bruteforce subdomains with wfuzz, fuzz in the Host header:

wfuzz -c -w /Discovery/DNS/deepmagic.com-prefixes-top500.txt -H "Host: FUZZ.example.com" -u "https://example.com"

While wfuzz is capable, sometimes using a tool that is specifically built for this (like gobuster or amass) might be easier and yield better results.


wfuzz offers a variety of payloads that can be used to fuzz with, including a list of numbers.

If I stumbled upon a an id parameter in JSON that used a guessable four digit number, I might fuzz it like so to see if I can access any accounts I don’t own:

wfuzz -c -z range,0000-9999 -X POST -H "Content-type: application/json" "https://example.com/myaccount" -d '{"id": "FUZZ"}'

The -z parameter is used to specify a payload type and the payload options. You can see the full list of payload’s with wfuzz -e payloads.

You might also notice that I changed the method from the default GET to POST with the -X option and added a body to my request with -d. This syntax should be familiar with you if you’ve every used curl before. Another reason why I love wfuzz!


If you’ve ever tested for injection vulnerabilities (like SQLi or command injection) then it is likely that your attempts have been blocked by a WAF (Web Application Firewall). WAFs are all fine and dandy but they’re not perfect.

It can be useful to fuzz common payloads to see if any might slip through the cracks

wfuzz -c -w Fuzzing/XSS/XSS-Somdev.txt -u "https://example.com?q=FUZZ" --hc 403

In this example, I used a Cross-site Scripting (XSS) wordlist to see if any common payloads weren’t blocked. This likely will not lead to a XSS bug right away, but might clue me in on what keywords or encoding methods might allow me to build a working payload.

If you’re into finding XSS bugs, fuzzing with Portswigger’s XSS Cheat Sheet can help you see what HTML tags and events are permitted so you can get an idea of how to build your own payload.

Password Spraying

Database leaks for a specific target can be a great asset when testing login pages, but with thousands of accounts to choose from, it can be hard to find valid credentials. Luckily, wfuzz can do this much faster than we can.

Password spraying is the act of guessing the password of many different accounts (not just one like in brute-force attacks). To achieve this, you need to tell wfuzz to fuzz in two separate locations each with its own payload like so:

wfuzz -c -m zip -w users.txt -w passwords.txt -X POST -u "https://example.com" -d "username=FUZZ&password=FUZ2Z" --sc 302

For fuzzing multiple locations with different payloads, you need to supply FUZ<payload #>Z. In this example FUZZ is associated with users.txt and FUZ2Z with passwords.txt.

I also supplied an iterator type of zip with the -m argument. The zip iterator type will match each of the payloads to the other, 1-to-1, so it is perfect for password spraying. If you’ve used Burp’s Intruder before, than the zip iterator is just like the Intruder’s Pitchfork attack type.

We can list the other iterator types with the -e options like we did for payloads.

Wrapping it all up

wfuzz does one thing (and only one thing) well: spit out a bunch of requests really fast. It’s up to you to make it an effective hacking too.

That means choosing the right wordlist for the job. There are tons of wordlists out there for different jobs. Don’t just limit yourself to SecLists. It’s a great wordlist and popular for a reason, but it’s popularity just means that a lot of other hunters are going to be using it too, so you’ll likely stumble across the same bugs they do.

So, Google around and find wordlists that work for you. Or, better yet, make your own as you hunt!

Also don’t go fuzzing around unless the program allows it. Sometimes there’s a request delay requirement and other times companies won’t permit the use of automated tools at all. Read the policy carefully! Otherwise, you may end up overwhelming the company’s servers.

Now, you have most of what you need to unleash the power of wfuzz and hunt more efficiently! Happy hunting!