Penetration Testing

A Detailed Guide on Wfuzz


Many tools have been developed that create an HTTP request and allow a user to modify their contents. Fuzzing works the same way. A user can send a similar request multiple times to the server with a certain section of the request changed. When that certain section is replaced by a variable from a list or directory, it is called fuzzing.

In this article, we will learn how we can use wfuzz, which states for “Web Application Fuzzer”, which is an interesting open-source web fuzzing tool. Since its release, many people have gravitated towards wfuzz, particularly in the bug bounty scenario. So, let’s dive into this learning process.

Table of content

  • Introduction to wfuzz
  • Setup
  • Wfpayload and Wfencode
  • Docker run wfuzz
  • Payloads
  • Subdomain Fuzzing
  • Directory Fuzzing
  • Saving fuzzing output
  • Basic wordlist filters
  • Double fuzzing
  • Login bruteforce
  • Cookie fuzzing
  • Header fuzzing
  • HTTP OPTIONS fuzzing
  • Fuzzing through Proxy
  • Authentication fuzz
  • Recursive fuzz
  • Printers and output
  • Encoders
  • Storing and restoring fuzz from recipes
  • Ignoring exceptions and errors
  • Filtering results
  • Sessions in wfuzz
  • Conclusion

Introduction to Wfuzz

Wfuzz is a python coded application to fuzz web applications with a plethora of options. It offers various filters that allow one to replace a simple web request with a required word by replacing it with the variable “FUZZ.”


To install wfuzz using pip, we can:

pip3 install wfuzz

The same could be achieved by installing from the source using git.

git clone

The help menu to see all the working options is as follows:

wfuzz -h
wfuzz --help

You can use a module by using “-z”

Wfpayload and Wfencode

When you install the tool from the source, compiled executables called wfpayload and wfencode are available. These are responsible for payload generation and encoding. They can be individually used. For example, the command to generate digits from 0 to 15 is as follows:

./wfpayload -z range,0-15

As you can see, there is a pycurl error. It can go away like so:

apt --purge remove python3-pycurl && apt install libcurl4-openssl-dev libssl-dev

Now, when you run wfencode, which is a module to encode a supplied input using a hash algorithm, there is no pycurl error now.

./wfencode -e md5 ignite

Docker run wfuzz

Wfuzz can also be launched using docker in the following way using the repo The respective command can be run by replacing the last variable wfuzz.

docker run -v $(pwd)/wordlist:/wordlist/ -it wfuzz


A payload in Wfuzz is a source of input data. The available payloads can be listed by executing:

wfuzz -e payloads

The detailed view can also be looked at using the slice filter:

wfuzz -z help --slice "list"

Subdomain Fuzzing

Subdomain discovery is extremely helpful in pentesting scenarios. Often, attackers launch attacks on subdomains rather than main domains and it can be fuzzed like so:

Here, -c color codes the output response codes
-Z specifies a URL to be input in scan mode and ignores any connection error
-w specifies the wordlist use while subdomain bruteforce.

wfuzz -c -Z -w subdomains.txt

The same can be achieved by providing the subdomain list inline too. Only, the payload (-z option) should be supplied in with “list” as an input. The list is supplied in the format ITEM1-ITEM2-ITEM3 like so:

wfuzz -z list,CVS-testphp-admin-svn
wfuzz -z list,CVS-testphp-admin-svn

Directory Fuzzing

Directories can be enumerated using wfuzz just like with gobuster by using a supplied wordlist. This can be done using a -w flag and inputting the path of the wordlist:

wfuzz -w wordlist/general/common.txt

As you can see in the above screenshot, all the results including page not found have been dumped which makes it tedious to go through the results and find pin in a haystack. Therefore, to sort the results out we can see the show code flag (–sc). Other such flags are:

  • –hc/sc CODE #Hide/Show by code in response
  • –hl/sl NUM #ide/Show by number of lines in response
  • –hw/sw NUM #ide/Show by number of words in response
  • –hc/sc NUM #ide/Show by number of chars in response
wfuzz -w wordlist/general/common.txt --sc 200,301

Saving fuzzing output

Wfuzz output can also be saved in multiple formats using the -f option.

-f option allows a user to input a file path and specify a printer (which formats the output) after a comma.

wfuzz -w wordlist/general/common.txt -f /tmp/output,csv --sc 200,301
cat /tmp/output

In place of csv, you can specify any one of the printers

wfuzz -e printers

Basic wordlist filters

There are certain sub-arguments that can be preceded by -z or -w filter to play around more with. These filters are:

–zP <params>: Arguments for the specified payload

–zD <default>: Default parameter for the specified payload

–zE <encoder>: Encoder for the specified payload

So, to specify a wordlist with the payload, we can do it like so:

wfuzz -z file --zD wordlist/general/common.txt --sc 200,301

To hide the HTTP response code 404, the same can be obtained like so:

wfuzz -z file --zD wordlist/general/common.txt --hc 404

Double fuzzing

Just like a parameter in a payload can be fuzzed using the keyword “FUZZ” multiple fuzzing is also possible by specifying keywords:

  • FUZ2Z – 2nd parameter
  • FUZ3Z – 3rd parameter
  • FUZ4Z – 4th parameter

And each parameter can be allotted its own wordlist. The first “-w” stands for first FUZZ. Second “-w” holds for the second FUZ2Z and so on.

wfuzz -w wordlist/general/common.txt -w wordlist/general/common.txt --hc 404

Login bruteforce

HTTP responses can be brute-forced using wfuzz. For example, testphp’s website makes a POST request to the backend and passes “uname” and “pass” as the arguments to a page userinfo.php

The same can be implemented using wfuzz like so:

-d argument specifies the post data to be sent along with the request

wfuzz -z file,wordlist/others/common_pass.txt -d "uname=FUZZ&pass=FUZZ"  --hc 302

As you can see, the correct credentials “test-test” have been found. We used a common file for both username and password. The same can be done by providing different files for both usernames and passwords like so:

-c is to color code the output response which can be skipped.

wfuzz -z file,users.txt -z file,pass.txt --sc 200 -d "uname=FUZZ&pass=FUZ2Z"

Cookie fuzzing

To send a custom cookie along a request to different fuzzed directories we can use the “-b” plug. This would add a cookie to the sent HTTP request.

Scenario useful:

  • Cookie poisoning
  • Session hijacking
  • Privilege Escalation
wfuzz -z file,wordlist/general/common.txt -b cookie=secureadmin -b cookie2=value2 --hc 404

In the above scenario, we have added 2 static cookies on multiple directories. Now, we can also fuzz the cookie parameter too like so:

wfuzz -z file,wordlist/general/common.txt -b cookie=FUZZ

Header fuzzing

HTTP header can be added in a request being sent out by wfuzz. HTTP headers can change the behaviour of an entire web page. Custom headers can be fuzzed or injected in an outgoing request

Scenarios useful:

  • HTTP Header Injections
  • SQL Injections
  • Host Header Injections
wfuzz -z file,wordlist/general/common.txt -H "X-Forwarded-By:" -H "User-Agent: Firefox"


There are various HTTP Request/Options methods available that can be specified by using the “-X” flag. In the following example, We have inserted the following options in a text file called options.txt

  • GET
  • HEAD
  • POST
  • PUT
wfuzz -c -w options.txt --sc 200 -X FUZZ “”

As you could see, three valid options returned a 200 response code.

The same can be input inline using the “list” payload like so:


Fuzzing through Proxy

Wfuzz can also route the requests through a proxy. In the following example, a Burp proxy is active on port 8080 and the request intercepted in the burp intercept as you can see.

wfuzz -z file,wordlist/general/common.txt -p localhost:8080

The same can also be achieved with SOCKS proxy like so:

wfuzz -z file,wordlist/general/common.txt -p localhost:9500:SOCKS5

Authentication fuzz

Wfuzz can also set authentication headers and provide means of authentication through HTTP requests.


  • –basic: provides basic Username and Password auth
  • –ntlm: windows auth
  • –digest: webserver negotiation through digest access

In the following example, I am providing a list inline with two variables and –basic input to bruteforce a website

wfuzz -z list,nonvalid-httpwatch --basic FUZZ:FUZZ

Recursive fuzz

-R switch can specify the levels of recursion while fuzzing directories or parameters. Recursion in simple terms means fuzzing at multiple different levels of directories like /dir/dir/dir etc

In the following example, we are recursing at level 1 with a list inline containing 3 directories: admin, CVS and cgi-bin. Note how a directory with – in its name can be supplied inline

wfuzz -z list,"admin-CVS-cgi\-bin" -R1

Printers and output

Printers in wfuzz refers to all the formats a payload’s output can be processed as. It can be viewed using -e succeeded by printers argument. Furthermore, “-o” flag can specify the format of the output too

wfuzz -e printers
wfuzz -o json -w wordlist/general/common.txt


Various encoders are available in wfuzz. One such encoder we saw earlier was md5. Other encoders can be viewed by using “-e” flag with encoders argument.

wfuzz -e encoders

One can fuzz a website for directories by using MD5 output like so:

wfuzz -z file,wordlist/general/common.txt,md5

Storing and restoring fuzz from recipes

To make scanning easy, wfuzz can save and restore sessions using the “–dump-recipe” and “–recipe” flag.

wfuzz -w wordlist/general/common.txt --dump-recipe /tmp/recipe --sc 200,301
wfuzz --recipe /tmp/recipe

Ignoring exceptions and errors

Often while fuzzing, there are various errors and exceptions that a website can throw. “-Z” option can make wfuzz ignore these errors and exceptions. First, we run a normal subdomain fuzzing routine and then with -Z option:

wfuzz -z list,support-web-none
wfuzz -z list,support-web-none -Z

As you could see, -Z ignores that error on the bottom. Further, any invalid response can also be hidden like so:

wfuzz -z list,support-web-none -Z --hc “XXX”


Filtering results

There are many filters available to manipulate a payload or output.

wfuzz --filter-help

These can be manipulated using “–filter, –slice, –field and –efield” arguments.

For example, to view raw responses of the payload sent and the complete HTTP request made, you can use “–efield r” option

wfuzz -z range --zD 0-1 -u --efield r

However, if only the intended URL is needed, one can do it by providing –efield url input.

wfuzz -z range --zD 0-1 -u --efield url --efield h

Similarly, to filter out results based on the response code and the length of the page (lines greater than 97), you can do it like:

wfuzz -z range,0-10 --filter "c=200 and l>97"

A detailed table of all the filters for the payloads can be found here.

Sessions in wfuzz

A session in wfuzz is a temporary file which can be saved and later picked up, re-processed and post-processed. This is helpful in situations where one result saved already needs alterations or an analyst needs to look for something in the results. “–oF” filter can save the session output to a file.

wfuzz --oF /tmp/session -z range,0-10

This session file can now be opened up again and consumed using the “wfuzzp” payload like so:

wfuzz -z wfuzzp,/tmp/session FUZZ

One such example of this filteration from a previously saved session is as follows where we find an SQL injection vulnerability by utilizing a Python regex designed to read responses after a request modifies a parameter by adding an apostrophe (‘) and fuzzing again. “-A” displays a verbose output.

The regex r.params.get=+’\’  adds apostrophe (‘) in the get parameter. r stands for a raw response.

wfuzz -z range,1-5 --oF /tmp/session
wfuzz -z wfuzzp,/tmp/session --prefilter "r.params.get=+'\''" -A FUZZ

As you can see, request number 4 throws an SQL error which indicates SQL injection. For more regex operations refer here.


Wfuzz is a versatile tool that can perform more than just directory enumeration and truly help a pentester in his analyses. It’s a fast scanner that is easy to use and coded in python for portability. Hope you liked the article. Thanks for reading.

Author: Harshit Rajpal is an InfoSec researcher and left and right brain thinker. Contact here