前言

基于漏洞的拒绝服务攻击主要是利用协议设计本身的缺陷,或者协议实现的漏洞,通过一些非正常的数据报使得受害主机在处理这些时出现异常,甚至导致受害主机崩溃。由于这类攻击主要是利用协议或其实现的漏洞来达到攻击效果,因此有时也称其为协议攻击。此类攻击一般可以通过打补丁或者在防火墙处过滤特定的异常数据报文等方式进行防御。

碎片(Teardrop)攻击

国内有些文献把这种攻击称为泪滴攻击。当数据报在不同的网络介质之间传输时,由于不同的网络介质及其链路层协议允许传输的数据报的最大长度不同,即最大传输单元MTU可能是不同的,当数据报从一个MTU较大的物理子网进入一个MTU相对较小的物理子网的时候,为了确保数据报能顺利到达目的地,就需要对原有的数据报进行分片。因此分片是IP协议实现中必须具备的功能。
很显然,有分片就必须有重组,因为数据报被分片以后,不同的片段会在网络中被独立转发,然而对于上层应用来说,还是希望得到原来完整的数据报。为了使得同数据报的不同分片能够在其目的端顺利重组,每个分片必须留下重组的线索,即必须遵从以下规则。

  1. 同一数据报的所有分片的标识号(即IP ID )必须相同。
  2. 每个分片必须指明其在原完整数据报中的相对位置,即偏移位置(Offset)。
  3. 每个分片必须指明其数据的长度。
  4. 每个分片必须说明其是否是最后一个分片,即其后是否还有其他的分片。

所有这些信息都包含在IP分组头中。
如果所有数据通信的参与方都完全按照上面的规范进行分片和重组则完全没有问题,但如果不是,如有意让不同分片的偏移位置有重叠的部分,可能问题就来了。碎片攻击的依据正是这里。
Teardrop本是一段用于拒绝服务攻击的程序名,该程序利用Windows 95、Windows NT、Windows3.1和低版本Linux中处理IP分片的漏洞,向受害者发送偏移地址重叠的UDP数据报分片,使得目标主机在将分片重组时出现异常错误,导致目标系统崩溃或重启。
假设原始数据报有1600字节数据(不含IP包头),以太网的MTU为1500字节,该数据报经过以太网传输时会被分成两个分片,第一个分片为1480字节(考虑20字节的IP头),偏移为0;第二个分片为120字节,偏移应该为1480字节。当接收方收到数据长度为1480字节的第一个分片数据包以后,如果收到第二个数据长度为120字节、偏移为1480字节的分片时,则将第二个数据包的数据长度和偏移加起来,作为两个数据分片的总长度(即1600字节)。由于已经复制了第一个分片的1480字节,因此系统从第二个分片中再复制1600-1 480=120字节数据到为重组开设的缓冲区中。
但是如果攻击者刻意修改第二个数据包的分片信息,比如,将偏移量设置为1200(分片长度仍为1200字节),那么结果就不一样了。在收到第一个分片后,如果接受者收到第二个偏移为1200、数据长度为120的分片时,系统计算1200+120=1320作为两个数据分片的总长度。为了确定应该从第二个分片中复制多少字节,系统需要用总长度减去第一个分片中已经复制的1480字节,结果得到1 320-1480=-160字节。由于系统采用的是无符号整数,则160相当于一个很大的整数,这时候系统处理就出现异常了。根据系统不同,出现异常的情况也不一样,但通常会导致堆栈损坏、IP 模块不可用和系统挂起等。老版本的Linux内核(1.x~2.0.x)和Windows操作系统( Win NT等)在处理这种重叠分片的时候都存在问题。
碎片攻击也有其他的变种,其中一种基于微小分片的攻击主要用于穿透防火墙,其基本思路为:假设防火墙只通过检查数据包的第一个分片来确定是否放行某个数据报,攻击者就可以通过IP分片技术将用户数据报(如TCP报文)切分为很小的片段,使TCP报头信息被分到两个分片中,比如将TCP的标志信息等划入后一个分片中,从而使得一些通过检查这些标志位进行过滤的防火墙因找不到标志位而放行这些数据分组。对付这种攻击可以采用的一个策略是在防火墙处设置分片数据包长度的下限,确保第一个分片中包含所有必需的头信息;或者防火墙在检测时进行数据包的重组,仅当重组后的数据包符合放行条件时,才放行相关的数据包分片。当然这种做法本身又为攻击者攻击防火墙创造了条件。

LAND攻击

LAND原是一段C语言编写的程序,该程序用于向受害者主机发送TCP SYN分组,这些分组的源IP地址和目的IP地址都被伪造成同一IP地址,即受害者的IP地址、源端口和目的端口被设置为相同的。这样,受害者收到来自攻击者的请求分组后,就会持续不断地给自己发送响应分组,最终导致受害者主机挂起、崩溃或者重启。所以LAND攻击也被命名为局域网拒绝(Local Area Network Denial,LAND)攻击。一些TCP/IP的早期实现版本容易受到LAND攻击的影响,不过总体而言,这是一个比较老旧(约在1997年出现)的攻击,现如今,绝大部分系统都已经修补了这个漏洞。此外,这种攻击也可以通过过滤伪造IP分组的方法进行有效防御。需要注意的是,LAND攻击和TCP SYN Flooding泛洪攻击是不同的

Ping of Death攻击

根据RFC791规范,IPv4版本协议的分组(包括分组头在内)的最大长度是65535字节(即2^16-1字节),该限制主要是源于IP头有一个描述分组总长度的字段,该字段的长度正是16比特。
另一方面,受物理网络MTU的限制,比如以太网的MTU是1500字节,当一个大的IP分组在经由数据链路层向另一个物理网络传输的时候往往需要被分割为多个IP分组(即IP分片),以确保每一个IP分片都不至于超过所在物理网络的MTU。在接收端再对这些IP分片进行重组。
每个IP报头的IP标识号和偏移量(Offset)字段用于支持分段的重组,其中IP标识号在每个分片中都一样,偏移量则定义了当前这个分片在原数据报中的相对位置。在IP报头中Offset字段的长度为13bit,Offset字段以8字节为一个单位,因此理论上最大的偏移为65528字节(即(2^13-1)×8字节)。这也就意味着,当一个IP分片的Offset字段设置为最大值的时候,它的数据载荷至多只能是7字节(65535-65528=7字节),否则原IP数据报就会超过IP分组的最大长度。
一个恶意的用户可以向受害者主机发送Offset字段设置为最大值、同时数据载荷又超过8字节的IP分片。当接收方重组所有IP分片的时候,将得到一个长度超过65535字节的IP分组,这将有可能导致接收方系统分配给该IP分组用于重组的内存缓冲区溢出,进而引起一系列其他的问题,如系统崩溃、死机或重启等。

Ping of Death攻击就是利用了IP实现时的这个漏洞,向受害者发送超长的Ping数据包,导致受害者系统异常。Ping命令是基于ICMP实现的,而ICMP是基于IP实现的,即ICMP报文要封装到IP分组中进行转发,考虑到IP报头20字节和ICMP报头8字节,那么正常情况下,一个ICMP报文的数据载荷应该不超过65535-20-8=65507字节。 Ping of Death通过向受害者主机发送一系列超过65507字节的Ping数据包导致系统拒绝服务。尽管现在绝大部分操作系统都已经修复了这个漏洞,恶意人员通过执行简单的Ping命令已经不足以使目标系统瘫痪,但经过精心设计的ICMP的实现还是有可能导致系统异常的。
值得一提的是,Ping of Death攻击,虽然源于Ping数据包的恶意发送,但实际上却和ICMP没多大关系,在这里ICMP只是数据载荷,其问题的根源还是IP分段重组的过程,因此其他所有基于IP进行数据转发的协议,诸如TCP、UDP和IGMP等都是有可能导致类似的攻击的。
2013年,微软的操作系统也发现了IPv6的Ping of Death漏洞,Windows操作系统的TCP/IP协议栈在处理到达的记性IMC Pv6数据报时,没能正确地处理好其内存分配事宜,可导致远程的DoS攻击。当年8月,微软官方修复了这个漏洞。