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
- Wfpayload and Wfencode
- Docker run wfuzz
- 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
- Storing and restoring fuzz from recipes
- Ignoring exceptions and errors
- Filtering results
- Sessions in wfuzz
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 https://github.com/xmendez/wfuzz.git
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 ghcr.io. The respective command can be run by replacing the last variable wfuzz.
docker run -v $(pwd)/wordlist:/wordlist/ -it ghcr.io/xmendez/wfuzz 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 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 http://FUZZ.vulnweb.com
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 http://testphp.vulnweb.com/FUZZ wfuzz -z list,CVS-testphp-admin-svn http://FUZZ.vulnweb.com/
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 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/FUZZ 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 http://testphp.vulnweb.com/FUZZ
To hide the HTTP response code 404, the same can be obtained like so:
wfuzz -z file --zD wordlist/general/common.txt --hc 404 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/FUZZ/FUZ2Z
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 http://testphp.vulnweb.com/userinfo.php
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" http://testphp.vulnweb.com/userinfo.php
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.
- Cookie poisoning
- Session hijacking
- Privilege Escalation
wfuzz -z file,wordlist/general/common.txt -b cookie=secureadmin -b cookie2=value2 --hc 404 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/
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
- HTTP Header Injections
- SQL Injections
- Host Header Injections
wfuzz -z file,wordlist/general/common.txt -H "X-Forwarded-By: 127.0.0.1" -H "User-Agent: Firefox" http://testphp.vulnweb.com/FUZZ
HTTP OPTIONS fuzzing
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
wfuzz -c -w options.txt --sc 200 -X FUZZ “http://testphp.vulnweb.com”
As you could see, three valid options returned a 200 response code.
The same can be input inline using the “list” payload like so:
wfuzz -z list,GET-HEAD-POST-TRACE-OPTIONS -X FUZZ http://testphp.vulnweb.com/
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 http://testphp.vulnweb.com/FUZZ
The same can also be achieved with SOCKS proxy like so:
wfuzz -z file,wordlist/general/common.txt -p localhost:9500:SOCKS5 http://testphp.vulnweb.com/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 httpwatch.com
wfuzz -z list,nonvalid-httpwatch --basic FUZZ:FUZZ https://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx
-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 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/FUZZ
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 http://testphp.vulnweb.com/FUZZ 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 http://FUZZ.google.com/ wfuzz -z list,support-web-none -Z http://FUZZ.google.com/
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” http://FUZZ.google.com/
There are many filters available to manipulate a payload or output.
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 http://testphp.vulnweb.com/artists.php?artist=FUZZ --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 http://testphp.vulnweb.com/artists.php?artist=FUZZ --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" http://testphp.vulnweb.com/listproducts.php?cat=FUZZ
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 http://testphp.vulnweb.com/listproducts.php?cat=FUZZ
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 http://testphp.vulnweb.com/artists.php?artist=FUZZ 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