ICS: Programming HW: Fuzzing

Go up to the ICS HW page (md) | view one-page version

Overview

In this assignment, you will be creating a network fuzzer, which is a program that will try out many different URL variants to see if any exist on a web server. Given a base URL, such as http://server.com/FUZZ, and a word list containing many items, it will replace the string FUZZ with each of the words in the word list, and see if that URL exists.

Credit: this homework is based heavily on Will Shand’s xfuzz assignment.

Background

Changelog

Any changes to this page will be put here for easy reference. Typo fixes and minor clarifications are not listed here.

Setup

This assignment must be done in a recent version of Python. The only additional package you will need is uvicorn – to install it, enter pip install uvicorn (or pip3 install uvicorn).

You will need a number of files from this repository to work on this assignment:

Calling the code

The provided code in args.py already handles the command line argument parsing. Run python3 fuzzer.py -h to see the various options. You are going to write the fuzz() function in fuzzer.py – the parameter passed into that function contains the parse command line arguments – you can print it to the screen during development to see how they are stored (but be sure to remove that print statement – and any others beyond what is required – before submission).

Writing the code

You have to write the fuzz() function in fuzzer.py (src) – remove the pass line that is there once you insert your own code. The intent is for you to use the urllib.request library; documentation on that can be found here.

For the basic fuzzing, you will likely need the urllib.request.urlopen() function and the status field of the object it returns.

For advanced fuzzing, you will want to create a urllib.request.Request object so that you can set more parameters.

Task 1: Basic fuzzing

The first task is to perform basic testing. Given a URL, such as http://server.com/FUZZ, you will replace FUZZ with each word in the word list file, and then try that URL to see if you get a response other than 404 (not found). You will do this by modifying the fuzz() function in the fuzzer.py (src) skeleton code. Try printing out the parameter to the function to see how the command-line arguments are passed into the function. You can see in the skeleton code how one might load a URL from a string.

When you are ready to test this, read the ‘Testing’ section, below, for easy ways to test it locally on your computer.

Output

The output for this assignment is very specific. Once you have completed the above task, any URL that does NOT return a 404 should display the output in the following EXACT format. (Note that you will modify what URLs to print later).

For example, if you were to call the fuzzer as: python3 fuzzer.py -u http://ffuf.me/cd/basic/FUZZ -w common.txt, then the output would be exactly:

200 http://ffuf.me/cd/basic/class
200 http://ffuf.me/cd/basic/development.log

Note that the output is the status number, a single space, and the URL. The order you print it out the lines does not matter, only the content on each line.

We are going to use this particular call the visible test when you submit your assignment (although we will use a smaller word list to save time, but it will contain both class and development.log). Other hidden tests will be used to grade your assignment.

DO NOT HAVE ANY OTHER OUTPUT! We are going to test it by doing a file comparison, so if you have any other output it will report as not the same, and you will fail that test. Again, the order of the lines in your output does not matter.

Task 2: Advanced fuzzing

There are a number of command-line parameters that the fuzzer.py file will accept. You have to implement usage of the others. You can find them all via python3 fuzzer.py -h. The remaining ones to implement are as follows. Note that these are already parsed for you; you just have to handle when those values are in the args parameter to the fuzz() function.

When we test your code, we will never give it invalid parameters, and there will always be a -u parameter and a -w parameter. So you do not have to error-check the parameters.

Testing

First test it locally, then test it remotely. Both are described below.

Local testing

Initially, as you are developing your code, you will want to test it out locally. One of the Python packages you installed is uvicorn, which is a small Python-based web server. To run it, you first need to save the server.py (src) file. This file has a urls list that is the set of URLs that it will respond with a 200 (OK) to; everything else it responds with a 404 (not found).

You are welcome to, and will eventually have to, change the elements in that list during testing – just note that each USLS part has to start with a forward slash. If you are running uvicorn, and you edit the server.py file, it should detect this and reload the contents so that you don’t have to restart it.

You will run your uvicorn server as follows:

uvicorn server:app --reload --port 5000

This runs the server on port 5000 on your computer. To test against this, you will run your fuzzer as follows:

python3 fuzzer.py -u http://localhost:5000/FUZZ -w common.txt

Note: it may be that your computer needs to use http://127.0.0.1:5000/FUZZ instead.

Also note: sometimes Macs have issues with port 5000. If that is the case, then try any other port (5001, 5002, etc.).

Following the output specifications described above, the output should be exactly as follows. Note that the order of the lines does not matter, as long as the format of each line is exact.

200 http://localhost:5000/.gitignore
200 http://localhost:5000/employers
200 http://localhost:5000/~admin

Uvicorn server.py edits

The server.py (src) file, which is what configures the uvicorn server, will need to be modified for you to test the additional command line flags. For example, you will may to try reporting 200 (OK) on alert.html, to test that your -e html works. Likewise, you will want to test out different server status values other than 200 to ensure that your -mc flag works.

Remote testing

As a remote test, you can try it with the URL of http://ffuf.me/cd/basic:

python3 fuzzer.py -u http://ffuf.me/cd/basic/FUZZ -mc 200 -w common.txt 

The output would be:

200 http://ffuf.me/cd/basic/class
200 http://ffuf.me/cd/basic/development.log

Please do NOT try it out against any other machines, as ITS will get very cranky at you for doing so.

Word lists

As mentioned above, the word list we are using is the common.txt file that we provide. You can also use word lists in the SecLists repository repository; you will probably want to use a word list in the Discovery/Web-Content/ directory. You do not need any word lists beyond the common.txt file for this assignment – the additional ones are just if you are interested.

There is also a common-reduced.txt file that contains only 100 words. It contains the five URLs that are expected to be found in the tests herein (.gitignore, employers, and ~admin for the uvicorn testing, and class and development.log for the fuff.me testing), as well as 95 other randomly chosen words from common.txt. This file is useful for testing, as it will take much less time to print the results.

Submission

You should only submit your fuzzer.py file to Gradescope. The only visible test will be the python3 fuzzer.py -u http://ffuf.me/cd/basic/FUZZ -w common-reduced.txt.