Updated 11 January 2019: Fixed syntax based on comments. Thank you!
If you are managing a Linux server, you’ve probably heard about DNS amplification attacks which make use of misconfigured DNS servers. DNS amplification is a DDoS technique which uses a large reply by DNS resolving the target. This is accomplished by spoofing the query with the source IP of the target victim to ask for a large DNS record, such as an ANY reply of the ROOT record or isc.org, which is most commonly found. The request itself is usually around 60-70 bytes, while the reply is as much as 2-3K. That’s why it’s called amplification. It will not only make your network participate in the attack, but it will also consume your bandwidth. More details can be found here.
Blocking these kinds of attacks can be tricky. However, there are some basic iptables rules that block most of it, using them in combination with fail2ban. As usual, your mileage might vary. The commands below were tested and executed on Ubuntu Server 16.04 LTS 64-bit.
Basically, it comes all down to adding these two IPtables rules:
iptables -A INPUT -p udp --dport 53 -m string --from 40 --algo bm --hex-string '|0000FF0001|' -m recent --set --name dnsanyquery iptables -A INPUT -p udp --dport 53 -m string --from 40 --algo bm --hex-string '|0000FF0001|' -m recent --name dnsanyquery --rcheck --seconds 60 --hitcount 3 -j DROP iptables -A INPUT -p tcp --dport 53 -m string --from 52 --algo bm --hex-string '|0000FF0001|' -m recent --set --name dnsanyquery iptables -A INPUT -p tcp --dport 53 -m string --from 52 --algo bm --hex-string '|0000FF0001|' -m recent --name dnsanyquery --rcheck --seconds 60 --hitcount 3 -j DROP
The first iptables rule looks for the incoming udp packets on port 53 and searches the first 50 of packet for hex string “0000FF0001” (which is equivalent to an ANY query).
The second iptables rule drops the packet if the source ip and query type (in this case “ANY”) matches and occurred more than one time in the past second.
Make sure to save your iptables rules, using something like
iptables-persistent, so that they stick when you reboot your server.
In case this approach doesn’t work for you, try using the following alternative, which makes use of Fail2ban instead of IPtables.
First edit the file /etc/fail2ban/jail.conf and add the following contents:
[iptables-dns] enabled = true ignoreip = 127.0.0.1 filter = iptables-dns action = iptables-multiport [name=iptables-dns, port="53", protocol=udp] logpath = /var/log/iptables/dns_reqs.log bantime = 86400 findtime = 120 maxretry = 1 [named-refused-udp] enabled = true [named-refused-tcp] enabled = true
Next, create a new fail2ban filter by creating a new file called /etc/fail2ban/filter.d/iptables-dns.conf and adding the following contents to it:
[Definition] failregex = fw-dns.*SRC=<HOST> DST failregex = ^.* security: info: client #.*: query \(cache\) './(NS|A|AAAA|MX|CNAME)/IN' denied ignoreregex =
After doing so, check using fail2ban-client status if you see the ‘iptables-dns’ jail listed. If fail2ban refuses to start, check your regex for typos using the following command:
fail2ban-regex /var/log/kern.log /etc/fail2ban/filter.d/iptables-dns.conf
That’s all folks! Any feedback or suggestions? Let me know in the comments!
Recommended further reading: A Realistic Approach and Mitigation Techniques for Amplifying DDOS Attack on DNS in Proceedings of 10th Global Engineering, Science and Technology Conference 2-3 January, 2015, BIAM Foundation, Dhaka, Bangladesh, ISBN: 978-1-922069-69-6 by Muhammad Yeasir Arafat, Muhammad Morshed Alam and Feroz Ahmed.