DNS Flood Attack是一种DDoS攻击,也是一种UDP Flood Attack,它的攻击方法和我们在上一节中描述的方法类似。
DNS Query Flood Attack也是一种DDoS攻击,但它的攻击方法和DNS Flood Attack不同。在DNS Flood Attack中,如图2-15所示,从客户端发到DNS服务器的请求数据包通常都是不正确的,但DNS服务器还是会消耗资源来检查数据包内容,当发现数据包格式有误后,不会真正去做DNS解析。即使这样,它还是会消耗大量DNS服务器的资源,从而造成DNS服务器无法响应新的客户端请求。
图2-15 DNS Flood Attack
但在DNS Query Flood Attack中,如图2-16所示,从客户端发到DNS服务器的请求报文的格式都是正确的,表面看上去都是正常的DNS请求,但是需要进行解析的域名则根本不存在,例如mk1234213334.net。被攻击的DNS服务器在接收到域名解析请求时,首先会在服务器上查找是否有对应的缓存,如果查找不到,并且该域名无法直接由服务器解析时,DNS服务器会向其上层DNS服务器递归查询域名信息。这种解析完全不存在的域名的过程给服务器带来了巨大的负载。当来自客户端的DNS请求数目过大且速度过快时,就会导致DNS服务器的资源被耗尽,无法响应新的客户端请求,从而达到DDoS攻击的效果。
图2-16 DNS Query Flood Attack
针对DNS服务最著名、最经典的攻击当属前文中介绍过的2016年发生的对Dyn公司(DNS服务提供商)的攻击了。
为了便于大家更深入地了解,我整理了两种利用iptables来实现的防御手段。在场景一中利用的是iptables的recent功能,在场景二中利用的是iptables的字符串过滤功能,具体内容请参看如下两个场景中的详细描述。
攻击者利用工具NetStress-NG生成大量随机的源地址,对目标DNS服务器进行攻击。NetStress-NG是一款压力测试工具,可以运行在Linux上,当然除了压力测试这个用途外,还可以作为发起DDoS攻击的工具。
测试环境如下所示。 虚拟化:VirtualBox 5.2 虚拟机:attacker(操作系统:Ubuntu 16.04.5 LTS, 相关软件:NetStress-NG, IP地址:192. 168.0.106) 虚拟机:target(操作系统:Ubuntu 16.04.5 LTS, 相关软件:bind9(端口53), IP地址:192. 168.0.108)
在虚拟机target上,首先确认bind9服务的状态。
zeeman@target:~$ sudo service bind9 status ● bind9.service - BIND Domain Name Server Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled) Drop-In: /run/systemd/generator/bind9.service.d └─50-insserv.conf-$named.conf Active: active (running) since Fri 2019-02-22 19:12:15 CST; 2h 47min ago Docs: man:named(8) Main PID: 981 (named) Tasks: 4 Memory: 14.4M CPU: 86ms CGroup: /system.slice/bind9.service └─981 /usr/sbin/named -f -u bind ... zeeman@target:~$
在PC客户端上,修改DNS配置,把DNS指向虚拟机target,再尝试解析域名zeeman-zhou.com。
E:\>ipconfig /all Windows IP配置 ... 无线局域网适配器 无线网络连接: 连接特定的DNS后缀 . . . . . . . . . : DHCP HOST 描述. . . . . . . . . . . . . . . : Intel(R) Wireless-N 7265 物理地址. . . . . . . . . . . . . : 48-45-20-A5-3F-61 DHCP已启用 . . . . . . . . . . . : 是 自动配置已启用 . . . . . . . . . . : 是 本地链接IPv6地址. . . . . . . . . : fe80::7c5d:56d1:56ac:21c%14(首选) IPv4地址 . . . . . . . . . . . . : 192.168.0.102(首选) 子网掩码 . . . . . . . . . . . . : 255.255.255.0 获得租约的时间 . . . . . . . . . : 2019年2月22日 21:12:17 租约过期的时间 . . . . . . . . . : 2019年2月23日 0:01:38 默认网关. . . . . . . . . . . . . : 192.168.0.1 DHCP 服务器 . . . . . . . . . . . : 192.168.0.1 DHCPv6 IAID . . . . . . . . . . .: 357057824 DHCPv6客户端DUID . . . . . . . . : 00-01-00-01-1F-72-4E-05-50-7B-9D-F5-88-2B DNS服务器 . . . . . . . . . . . .: 192.168.0.108 TCPIP上的NetBIOS . . . . . . . .: 已启用 ... E:\>ping zeemanzhou.com 正在 Ping zeemanzhou.com [192.168.100.100] 具有32字节的数据:
在确认虚拟机target上的DNS服务运行正常后,我们需要尝试进行攻击。在虚拟机attacker上,利用工具NetStress-NG对运行在虚拟机target上的DNS服务发起攻击。
zeeman@attacker:~$ sudo ./netstress-3.0.7/netstress.fullrandom -d target -P 53 -a dns -n 2 -t a ---------- netstress stats ---------- PPS: 10233 BPS: 10479104 MPS: 9.99 Total seconds active: 16 Total packets sent: 163736 ------------------------------------- ---------- netstress stats ---------- PPS: 10176 BPS: 10420288 MPS: 9.94 Total seconds active: 16 Total packets sent: 162817 ------------------------------------- zeeman@target:~$
在虚拟机target上,可以利用tcpdump查看攻击包的报文信息,从中可以发现刚才运行在虚拟机attacker上的NetStress-NG瞬间生成了海量的DNS访问请求。源地址是随机生成的,DNS的请求也是随机生成的,但它们也有一定的规律,都是以mk开头,跟着10个数字,例如mk1206692583.net。
zeeman@target:~$ sudo tcpdump -nn -XX -vvv udp port 53 tcpdump: listening on enp0s3, link-type EN10MB (Ethernet), capture size 262144 bytes 22:08:31.799776 IP (tos 0x0, ttl 64, id 58399, offset 0, flags [none], proto UDP (17), length 62) 9.228.239.36.1379 > 192.168.0.108.53: [udp sum ok] 53527+ A? mk1206692583.net. (34) 0x0000: 0800 27b0 7447 0800 27a8 0743 0800 4500 ..'.tG..'..C..E. 0x0010: 003e e41f 0000 4011 dc72 09e4 ef24 c0a8 .>....@..r...$.. 0x0020: 006c 0563 0035 002a 09f2 d117 0100 0001 .l.c.5.*........ 0x0030: 0000 0000 0000 0c6d 6b31 3230 3636 3932 .......mk1206692 0x0040: 3538 3303 6e65 7400 0001 0001 583.net..... 22:08:31.799781 IP (tos 0x0, ttl 64, id 12634, offset 0, flags [none], proto UDP (17), length 62) 42.34.108.25.1445 > 192.168.0.108.53: [udp sum ok] 34327+ A? mk1907568192.net. (34) 0x0000: 0800 27b0 7447 0800 27a8 0743 0800 4500 ..'.tG..'..C..E. 0x0010: 003e 315a 0000 4011 f205 2a22 6c19 c0a8 .>1Z..@...*"l... 0x0020: 006c 05a5 0035 002a b777 8617 0100 0001 .l...5.*.w...... 0x0030: 0000 0000 0000 0c6d 6b31 3930 3735 3638 .......mk1907568 0x0040: 3139 3203 6e65 7400 0001 0001 192.net..... 22:08:31.799858 IP (tos 0x0, ttl 64, id 56223, offset 0, flags [none], proto UDP (17), length 62) 145.57.245.69.1371 > 192.168.0.108.53: [udp sum ok] 43799+ A? mk1842915652.net. (34) 0x0000: 0800 27b0 7447 0800 27a8 0743 0800 4500 ..'.tG..'..C..E. 0x0010: 003e db9f 0000 4011 577c 9139 f545 c0a8 .>....@.W|.9.E.. 0x0020: 006c 055b 0035 002a a87c ab17 0100 0001 .l.[.5.*.|...... 0x0030: 0000 0000 0000 0c6d 6b31 3834 3239 3135 .......mk1842915 0x0040: 3635 3203 6e65 7400 0001 0001 652.net..... ... 267 packets captured 9544 packets received by filter 9217 packets dropped by kernel zeeman@target:~$
在PC客户端上,再次尝试解析域名 www.zeemanzhou.com ,发现已经无法解析了,DNS服务器没有响应。这也表明刚才进行的攻击成功了,达到了攻击效果。
E:\>ping www.zeemanzhou.com Ping请求找不到主机www.zeemanzhou.com。请检查该名称,然后重试。
下面,我们尝试一种基于虚拟机target上的iptables的防御方式。这种防御方式可以理解为是一种被动的方式,其具体的实现原理也比较简单,即当收到第一次DNS Query请求时,会记录下这次请求的基本信息,例如源地址等,然后直接DROP掉。如果是攻击流量或伪造的源地址,那这种请求是不会再重发的,如果是正常的客户端,则会再次发请求。当正常客户端再次发请求时,iptables会对比之前的记录,存在才会放行,并认为是正常的DNS Query请求。为实现这个思路,需要利用iptables的recent模块,这个模块有两个比较重要的参数需要做些调整,一个是ip_list_tot,另一个是ip_pkt_list_tot。这里的ip_list_tot参数值可以设为50 000,如果这个值设置得过小,会达不到效果,如果设得过大,会浪费系统资源,它的大小是需要根据攻击情况进行调整的。
zeeman@target:~$ sudo modprobe xt_recent ip_list_tot=50000 ip_pkt_list_tot=2 zeeman@target:~$ sudo head /sys/module/xt_recent/parameters/* ==> /sys/module/xt_recent/parameters/ip_list_gid <== 0 ==> /sys/module/xt_recent/parameters/ip_list_hash_size <== 65536 ==> /sys/module/xt_recent/parameters/ip_list_perms <== 420 ==> /sys/module/xt_recent/parameters/ip_list_tot <== 50000 ==> /sys/module/xt_recent/parameters/ip_list_uid <== 0 ==> /sys/module/xt_recent/parameters/ip_pkt_list_tot <== 2 zeeman@target:~$ sudo iptables -I INPUT -p udp --dport 53 -d 192.168.0.108 -m state --state NEW -m recent --name dnsuser --set -j DROP zeeman@target:~$ sudo iptables -I INPUT -p udp --dport 53 -d 192.168.0.108 -m recent --update --name dnsuser -j ACCEPT zeeman@target:~$ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT udp -- anywhere localhost udp dpt:domain recent: UPDATE name: dnsuser side: source mask: 255.255.255.255 DROP udp -- anywhere localhost udp dpt:domain state NEW recent: SET name: dnsuser side: source mask: 255.255.255.255 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination zeeman@target:~$
在虚拟机attacker上,利用工具NetStress-NG对运行在虚拟机target上的DNS服务再次发起攻击。
zeeman@attacker:~$ sudo ./netstress-3.0.7/netstress.fullrandom -d target -P 53 -a dns -n 2 -t a
在PC客户端上修改DNS配置,指向虚拟机target,尝试解析域名 zeemanzhou.com ,结果如下所示。我们可以看到,解析是可以成功的,说明刚才配置的iptables策略生效了。
E:\>ping zeemanzhou.com 正在Ping zeemanzhou.com [192.168.100.100]具有32字节的数据:
进行DNS解析的同时,我们在虚拟机target上查看文件/proc/net/xt_recent/dnsuser,可以看到源地址已经被记录到列表中。过一段时间后再次查看,发现文件里已经找不到源地址192.168.0.101了,因为它被其他进行攻击的源地址给覆盖掉了。
zeeman@target:~$ sudo cat /proc/net/xt_recent/dnsuser |grep 192.168.0.101 src=192.168.0.101 ttl: 128 last_seen: 4295099559 oldest_pkt: 2 4295099309, 4295099559 zeeman@target:~$ sudo cat /proc/net/xt_recent/dnsuser |grep 192.168.0.101 zeeman@target:~$
在这个场景中,攻击者利用工具NetStress-NG生成大量随机的源地址,对目标DNS服务器进行攻击。
测试环境如下所示。 虚拟化:VirtualBox 5.2 虚拟机:attacker(操作系统:Ubuntu 16.04.5 LTS, 相关软件:NetStress-NG, IP地址:192. 168.43.217) 虚拟机:target(操作系统:Ubuntu 16.04.5 LTS, 相关软件:bind9(端口53), IP地址:192. 168.43.19)
除了上述被动的防御方式,我们还可以考虑类似UDP Flood的防御方式,比如找到攻击的特征信息,然后进行过滤。在这个例子中,我们可以看到所有查询的域名格式都类似于mk1234567890.net,我们可以根据这个特征,进行简单的字符串过滤防御,同样可以达到防御的效果。在虚拟机target上,设置如下iptables规则。
zeeman@target:~$ sudo iptables -I INPUT -p udp --dport 53 -m string --string "mk" --algo kmp -j DROP zeeman@target:~$ sudo iptables -nvL Chain INPUT (policy ACCEPT 6 packets, 240 bytes) pkts bytes target prot opt in out source destination 0 0 DROP udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 STRING match "mk" ALGO name kmp TO 65535 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 11 packets, 1176 bytes) pkts bytes target prot opt in out source destination zeeman@target:~$
在虚拟机attacker上,利用工具NetStress-NG对运行在虚拟机target上的DNS服务发起攻击。
zeeman@attacker:~$ sudo ./netstress-3.0.7/netstress.fullrandom -d target -P 53 -a dns -n 2 -t a
在PC客户端上,修改DNS配置,指向虚拟机target,尝试解析域名zeemanzhou.com。结果如下所示,可以看到,解析是可以成功的。
E:\>ping zeemanzhou.com 正在Ping zeemanzhou.com [192.168.100.100]具有32字节的数据:
在虚拟机target上,我们可以对iptables设置的策略进行查看,可见大量的攻击包都已经被DROP掉了,有30个包也被ACCEPT了,有效地对攻击进行了防御,iptables设置的策略也起到了防御的效果。
zeeman@target:~$ sudo iptables -nvL Chain INPUT (policy ACCEPT 30 packets, 4570 bytes) pkts bytes target prot opt in out source destination 905K 56M DROP udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 STRING match "mk" ALGO name kmp TO 65535 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 43 packets, 4685 bytes) pkts bytes target prot opt in out source destination zeeman@target:~$