The top-performing bug bounty hunters rely heavily on automation to make their hacking processes more efficient, according to ethical hacker, author and security engineer Vickie Li. In fact, Li wrote in her book, Bug Bounty Bootcamp: The Guide to Finding and Reporting Web Vulnerabilities, the majority of new entries in the CVE catalog now feature bugs researchers found through automated fuzzing.
Fuzzing, or fuzz testing, is a technique that involves feeding an application invalid and unexpected data, with the goal of soliciting errors and exceptions that might point to a bug. Web application fuzzing is a type of fuzzing that specifically targets common web vulnerabilities.
In her book, Li broke fuzzing into the following four steps:
- Determine the data injection points. Identify how and where users can give the application input and which vulnerabilities these points of entry might be susceptible to.
- Decide on the payload list. Based on the injection points and possible vulnerabilities in play, decide what data to inject.
- Fuzz. Use an automated fuzzing tool, such as the open source fuzzer Wfuzz, to send the payload list to the data injection points.
- Monitor the results. Examine server responses for indications of possible vulnerabilities.
In this excerpt from Chapter 25, Li explains how to use Wfuzz, an open source fuzzer, to search for bugs in web applications.
More on Bug Bounty Bootcamp
Check out author Vickie Li's advice for hunting bugs as a novice ethical hacker in our Q&A.
Download the full chapter on how to use fuzzers to conduct automatic vulnerability discovery.
Fuzzing with Wfuzz
Now that you understand the general approach to take, let's walk through a hands-on example using Wfuzz, which you can install by using this command:
$ pip install wfuzz
Fuzzing is useful in both the recon phase and the hunting phase: you can use fuzzing to enumerate filepaths, brute-force authentication, test for common web vulnerabilities, and more.
During the recon stage, try using Wfuzz to enumerate filepaths on a server. Here's a command you can use to enumerate filepaths on example.com:
$ wfuzz -w wordlist.txt -f output.txt --hc 404 --follow http://example.com/FUZZ
The -w flag option specifies the wordlist to use for enumeration. In this case, you should pick a good path enumeration wordlist designed for the technology used by your target. The -f flag specifies the output file location. Here, we store our results into a file named output.txt in the current directory. The --hc 404 option tells Wfuzz to exclude any response that has a 404 status code. Remember that this code stands for File Not Found. With this filter, we can easily drop URLs that don't point to a valid file or directory from the results list. The --follow flag tells Wfuzz to follow all HTTP redirections so that our result shows the URL's actual destination.
Let's run the command using a simple wordlist to see what we can find on facebook.com. For our purposes, let's use a wordlist comprising just four words, called wordlist.txt:
Run this command to enumerate paths on Facebook:
$ wfuzz -w wordlist.txt -f output.txt --hc 404 --follow http://facebook.com/FUZZ
Let's take a look at the results. From left to right, a Wfuzz report has the following columns for each request: Request ID, HTTP Response Code, Response Length in Lines, Response Length in Words, Response Length in Characters, and the Payload Used:
* Wfuzz 2.4.6 - The Web Fuzzer *
Total requests: 4
ID Response Lines Word Chars Payload
000000004: 200 20 L 2904 W 227381 Ch "secure"
Total time: 1.080132
Processed Requests: 4
Filtered Requests: 3
You can see that these results contain only one response. This is because we filtered out irrelevant results. Since we dropped all 404 responses, we can now focus on the URLs that point to actual paths. It looks like /secure returned a 200 OK status code and is a valid path on facebook.com.
Once you've gathered valid filepaths on the target, you might find that some of the pages on the server are protected. Most of the time, these pages will have a 403 Forbidden response code. What can you do then?
Well, you could try to brute-force the authentication on the page. For example, sometimes pages use HTTP's basic authentication scheme as access control. In this case, you can use Wfuzz to fuzz the authentication headers, using the -H flag to specify custom headers:
$ wfuzz -w wordlist.txt -H "Authorization: Basic FUZZ" http://example.com/admin
The basic authentication scheme uses a header named Authorization to transfer credentials that are the base64-encoded strings of username and password pairs. For example, if your username and password were admin and password, your authentication string would be base64("admin:password"), or YWRtaW46cGFzc3dvcmQ=. You could generate authentication strings from common username and password pairs by using a script, then feed them to your target's protected pages by using Wfuzz.
Another way to brute-force basic authentication is to use Wfuzz's --basic option. This option automatically constructs authentication strings to brute-force basic authentication, given an input list of usernames and passwords. In Wfuzz, you can mark different injection points with FUZZ, FUZ2Z, FUZ3Z, and so on. These injection points will be fuzzed with the first, second, and third wordlist passed in, respectively. Here's a command you can use to fuzz the username and password field at the same time:
$ wfuzz -w usernames.txt -w passwords.txt --basic FUZZ:FUZ2Z http://example.com/admin
The usernames.txt file contains two usernames: admin and administrator. The passwords.txt file contains three passwords: secret, pass, and password. As you can see, Wfuzz sends a request for each username and password combination from your lists:
* Wfuzz 2.4.6 - The Web Fuzzer *
Total requests: 6
ID Response Lines Word Chars Payload
000000002: 404 46 L 120 W 1256 Ch "admin – pass"
000000001: 404 46 L 120 W 1256 Ch "admin – secret"
000000003: 404 46 L 120 W 1256 Ch "admin – password"
000000006: 404 46 L 120 W 1256 Ch "administrator – password"
000000004: 404 46 L 120 W 1256 Ch "administrator – secret"
000000005: 404 46 L 120 W 1256 Ch "administrator – pass"
Total time: 0.153867
Processed Requests: 6
Filtered Requests: 0
Other ways to bypass authentication by using brute-forcing include switching out the User-Agent header or forging custom headers used for authentication. You could accomplish all of these by using Wfuzz to bruteforce HTTP request headers.
Testing for common web vulnerabilities
Finally, Wfuzz can help you automatically test for common web vulnerabilities. First of all, you can use Wfuzz to fuzz URL parameters and test for vulnerabilities like IDOR and open redirects. Fuzz URL parameters by placing a FUZZ keyword in the URL. For example, if a site uses a numeric ID for chat messages, test various IDs by using this command:
$ wfuzz -w wordlist.txt http://example.com/view_message?message_id=FUZZ
Then find valid IDs by examining the response codes or content length of the response and see if you can access the messages of others. The IDs that point to valid pages usually return a 200 response code or a longer web page.
You can also insert payloads into redirect parameters to test for an open redirect:
$ wfuzz -w wordlist.txt http://example.com?redirect=FUZZ
To check if a payload causes a redirect, turn on Wfuzz's follow (--follow) and verbose (-v) options. The follow option instructs Wfuzz to follow redirects. The verbose option shows more detailed results, including whether redirects occurred during the request. See if you can construct a payload that redirects users to your site:
$ wfuzz -w wordlist.txt -v –-follow http://example.com?redirect=FUZZ
Finally, test for vulnerabilities such as XSS and SQL injection by fuzzing URL parameters, POST parameters, or other user input locations with common payload lists.
When testing for XSS by using Wfuzz, try creating a list of scripts that redirect the user to your page, and then turn on the verbose option to monitor for any redirects. Alternatively, you can use Wfuzz content filters to check for XSS payloads reflected. The --filter flag lets you set a result filter. An especially useful filter is content~STRING, which returns responses that contain whatever STRING is:
$ wfuzz -w xss.txt --filter "content~FUZZ" http://example.com/get_user?user_id=FUZZ
For SQL injection vulnerabilities, try using a premade SQL injection wordlist and monitor for anomalies in the response time, response code, or response length of each payload. If you use SQL injection payloads that include time delays, look for long response times. If most payloads return a certain response code but one does not, investigate that response further to see if there's a SQL injection there. A longer response length might also be an indication that you were able to extract data from the database.
The following command tests for SQL injection using the wordlist sqli.txt. You can specify POST body data with the -d flag:
$ wfuzz -w sqli.txt -d "user_id=FUZZ" http://example.com/get_user
More about Wfuzz
Wfuzz has many more advanced options, filters, and customizations that you can take advantage of. Used to its full potential, Wfuzz can automate the most tedious parts of your workflow and help you find more bugs. For more cool Wfuzz tricks, read its documentation at https://wfuzz.readthedocs.io/.
Excerpted from Bug Bounty Bootcamp: The Guide to Finding and Reporting Web Vulnerabilities by Vickie Li. Copyright © 2021 by Vickie Li. Excerpted by permission of No Starch Press. All rights reserved. No part of this excerpt may be reproduced or reprinted without permission in writing from the publisher.
About the author
Vickie Li is a developer and security researcher experienced in finding and exploiting vulnerabilities in web applications. She has reported vulnerabilities to firms such as Facebook, Yelp and Starbucks and contributes to a number of online training programs and technical blogs. She can be found at https://vickieli.dev/, where she blogs about security news, techniques and her latest bug bounty findings.