In this assignment you will explore a class of Denial of Service (DoS) attacks known as amplification attacks. Although there are several protocols susceptible to amplification, for this project we will be using DNS amplification. After seeing the effects of the amplification attack on a target web server, you'll program an appliance to protect the web server from the attack.
Although the attack script we are providing cannot be used exactly as-is to attack a real server, the necessary principles are there. Therefore this project comes with two important caveats:
1) We are counting on you to be responsible and use the provided code ONLY to learn about DNS, amplification attacks and DoS, and protecting against these attacks, and NOT to use the code or the knowledge you gain to do anything malicious to others.
2) DO NOT DISTRIBUTE this code to others, so they cannot use it for any malicious purposes either.
Before we begin, let's take a look at the topology we'll be using for this project:
svr (10.0.0.4) | | firewall (s1) | | switch (s2) / | \ | | | h1 h2 dns (10.0.0.1)
The host named
svr will run the web server that we'll be attacking, and
dns will run the innocent DNS server that we'll take advantage of to amplify our attack. The hosts
h2 are ordinary client / end hosts that we can use to retrieve web pages from the
svr or launch our DoS attack. The switch
s2 is an ordinary learning switch, but
s1 is different.
s1 is configured as a blacklist firewall with no rules, meaning all traffic is allowed through. It also has hooks in it to send DNS traffic to the controller where the function you write will inspect the traffic and either allow the DNS packets to pass through, or block them. The default behavior we've provided you to start with is to simply let all traffic through. This firewall differs from the one in Project 2, in that you will define blocking behavior as a function, not as a list of rules read from a configuration file.
The two switches are connected to each other by a high-bandwidth link. The two servers (
dns) are connected by moderate-bandwidth links, and the hosts (
h2) are connected by low-bandwidth links. In this project we observe how a host with limited bandwidth can use an amplification attack to saturate much larger network links.
amplify-dns.py- script that runs a DNS amplification attack
topo.py- the topology for the mininet network
start-topology.sh- shell script to launch the topology (
topo.py) and start the DNS server and web server inside the mininet environment
start-pyretic.sh- shell script to start pyretic
dns_firewall.py- contains a function that gets called on every DNS packet that the firewall (
s1) sees; this is the only file you need to turn in, and should be the only one you modify
firewall.py- the firewall (
s1) policy: calls the function on dns_firewall.py on every DNS packet, and simply forwards all non-DNS traffic
pyretic_switch.py- a standard learning switch policy, which is used for the regular switch (
dns_amplification_prevention.py- the main file for the Pyretic controller
bind/- this directory contains configuration files for the bind9 DNS server
http/- this directory contains the web server and a web page that can be retrieved from the server
impacket/- this directory contains the impacket library, which is used by the
ryu-update/- this directory contains the files needed to install the DNS parser into your Ryu configuration - already configured in the class VM
submit.py- this file is used to submit your file across the Internet to the auotgrader server.
If you have changed the number of cores in the course VM from one to anything else, please change this back. There are known issues with running with anything other than one core, but it's not known why it happens. This project MUST be run on a single core VM.
First, update your git repository to get the Project 6 code:
git commit -a -m "Saving work"
git pull --rebase
For this project, we will be using a new automatic submission system provided by Udacity. It relies on a Git submodule (think of it like a nested repository containing an external dependency) that needs to be initialized. Next, we need to initialize this submodule:
git submodule init
git submodule update
Provided you are using the course VM provided at the start of the class, this is all that's required by you to get started! In the highly unlikely event that you have been using your own development environment for this course, please post privately on Piazza for instructions on configuring this project's dependencies. We highly discourage this practice, especially for this project. It's far easier for all parties involved to use the course VM!
Once you have completed the configuration section, we can start the network and launch our attack. We created scripts to help launch the mininet topology and pyretic:
./start-topology.shto start the mininet topology (
In another terminal window,
./start-pyretic.sh to start pyretic
Note: In the course of running things, you may see some messages in the pyretic output that say "ERROR PUSHING MESSAGE". It is safe to ignore this message, it does not affect the correctness of the project.
These scripts should start the DNS server and web server inside the mininet environment automatically. Let's test those and make sure they're working.
mininet> h1 dig @10.0.0.1 www.cs6250.com (If that doesn't work, you can try running dig locally on the DNS server to see if it's a problem with the DNS server or with connectivity between the hosts.
dns dig @localhost www.cs6250.com)
mininet> h2 ping -c 10 svrto confirm connectivity and see what the latency to the web server is. Make a note of the RTT times you see here.
mininet> h2 wget http://10.0.0.4 to make sure the web server is working. Make a note of how long it took to download the file. It should be somewhere around 4 seconds.
Now that you've seen the latency (RTT time) and throughput (time to wget the web page) to the web server in normal conditions, let's launch the attack and see how the web server fairs when it's being DoSed. The attack script we've provided issues a query for the www.cs6250.com domain but spoofs the web server's IP as the source address in the IP header, so the DNS server's replies will be sent to the web server instead of back to the attacking host. It takes two parameters. The first parameter is the address of the DNS server that will be used for the attack, and the second is the target of the attack (the web server,
svr, in this case).
mininet> h1 python ./amplify-dns.py 10.0.0.1 10.0.0.4 & Note the & on the end runs it in the background so we can keep working in Mininet while the attack continues.
Now that the attack is going, let's see how the web server performs.
mininet> h2 ping -c 10 svr Note that the RTT latency is now much larger than before. (It's possible you may even see some packet loss.)
mininet> h2 wget http://10.0.0.4 This should now take much longer than it took originally.
Now that you've seen what the attack does, it's time to modify the firewall (
s1) to block it. For starters, let's just block all DNS traffic. Before we modify the files, we need to clean up the simulation. To do this, select your pyretic terminal and use
CTRL+c to kill the process. At the Mininet CLI, type
exit to terminate the CLI, and then type
sudo mn -c at the prompt to terminate the simulated topology and hosts. You should issue these commands in your terminals whenever you intend to edit
dns_firewall.py, and then restart the simulation with the two helper scripts in step 1.
dns_firewall.py has a function that will be called every time
s1 receives a DNS packet. Modify it to change it's policy from allowing all DNS packets to blocking DNS responses. You can add your code to the function provided there, and you can also add any global variables you need. Some starter code is provided to parse the DNS packets for you, so you can use the variables the parser extracted from the packet for you. To allow a packet through, simply return it from the function; to block a packet, return
Note: Be careful with print statements in this function. The function is called on every single DNS packet that the switch sees, which is a lot when the attack is underway. Since output statements are also relatively slow to execute (compared to other lines of code), print statements that are executing on every single function call can potentially overload the controller itself, turning the DoS attack against the web server into a DoS on pyretic (even if your policy correctly drops the attack traffic). Conditional output may be okay, if the condition is infrequent enough. It also may be okay to use some print statements for debugging, if you like to debug that way, so long as you take them back out before testing to see if your policy actually works under attack conditions. In general, once your submission is complete, you should remove all print statements before making your final submissions.
Now start up mininet and test your policy. Run steps 1-8 again (you can skip step 3, running dig). If your policy works, you should now see comparable performance both before and during the attack.
There's just one problem now. Run
mininet> svr dig @10.0.0.1 www.cs6250.com. Uh-oh! The web server can't issue legitimate DNS requests anymore! (You can also stop the attack and try this; it should still fail even when there is no attack.)
We'd like to allow matched pairs of queries and their responses, while blocking any gratuitous responses (that is, responses to queries that we haven't seen). Modify
dns_firewall.py to monitor DNS queries that pass through the firewall (and allow them to pass, of course), then to check any DNS responses against previously seen queries and allow them if they match an earlier query, but block them otherwise. DNS queries contain a transaction ID field with a randomly-assigned number. DNS responses also have a transaction ID that matches the transaction ID of the queries they are responding to. This is normally used to match responses to their queries, in the event that a host issues multiple queries in a short time, and you can also use it for matching responses to queries.
Now test your new policy! Start mininet and pyretic and make sure the server can make DNS queries to the DNS server (step 11). Then run steps 1-8 again (you can skip step 3) to make sure it is still effective at blocking the attack.
This project takes advantage of a remote Udacity Autograder. When you are finished, you can submit your file for grading with the command
python submit.py. The autograder will ask for a username and password, you should use your GT username and password (the same credentials used to log into T-Square). You will also be asked after the first submission if you would like to
Save the jwt?. This is referring to your credentials, so entering
y here will prevent you from having to enter your credentials on subsequent submissions.
The autograder is unit test based, and will return to you text based feedback indicating which tests have failed. You can submit as many times as you like. Your last submission will be the one counted for your final grade.
You MUST still submit your code to T-Square. We will use this as an official backup in case there is a discrepancy with what the autograder has recorded and your expectations.
To recap, the desired workflow for turn-in looks like this:
dns_firewall.pyfile that you used for your final autograder submission to T-Square.
You CANNOT share the code you write for
dns_firewall.py, or the output from the autograder. You CAN share the output of the commands you run during the Instructions section of the project on piazza for the purposes of comparing results or troubleshooting.
|2 pts||Correct Submission||for turning in |
|4 pts||Firewall Implementation||for allowing the web server to make DNS queries and receive the legitimate responses to those queries. For full credit, the firewall should be well formed, for example it should allow only a single response to a legitimate query, multiple outstanding queries should be supported, etc.|
|4 pts||Blocking the Attack||for successfully blocking DNS amplification attacks against the web server.|