信息安全课程5:IP协议安全

2 年前 · 来自专栏 信息安全课程

本节讨论IP协议及相关的安全问题。

IP协议是网络中最繁忙的协议。IP协议是一种best efforts协议,不保证可靠性,数据包可能重复、丢失;无连接协议,同一个连接中的多个报文被独立对待。IP协议主要定义了数据传送的基本单位;执行路由功能;主要规定了主机和路由器应该如何处理数据包;在什么情况下产生错误信息;以及什么情况下应该丢弃数据包。

下面结合IP协议的头部来详细分析一下以上功能。

首先看一下IP数据包的位置:

思考一下:Frame Header的长度是多少?

接下来看一下IP包头的具体的结构:

对照着具体的实例看看。

下面我们一个字段一个字段来分析一下。

  • 首先是4 bit的协议字段:目前是4,代表IPv4;如果是IPv6,会有一个新的协议头部。
  • HLEN,表示包中IP头部的长度,它的单位是32 位,也就是4个字节,因此上面包中的5指示该数据包的IP头部的长度是4*5=20字节。
  • ToS:总共有八位,代表不同类型的服务,其中只能设置一位。常见的包括 min delay, 0x10; max throughput, 0x08;max reliability, 0x40; min cost, 0x20。
  • 接下来是Total Length【两个字节】。以字节为单位的报文的长度。
  • IDent,flags和fragment offset【两个字节,3位,13位】:一起用于数据包的分片和重组;后面详细讨论。【也是针对IP协议发起攻击的主要利用的字段】
  • TTL:Time to Live,由发送者启动,然后每经过一个路由器就减一。如果到达某一个路由器的时候数据包的TTL变为0,那么就被丢弃。可以有效地防止路由循环。
    • Example: ping –t TTL IP allows us to specify the TTL field
    • 思考: 如果修改数据包的TTL(定制数据包),一般需要root权限,那么为什么我们可以通过ping程序来修改TTL? 【实际上,发送ICMP数据包需要root权限】
    • 思考:能不能找到一个TTL应用的例子?
    • TraceRoute是如何实现的?
  • TYPE:IP报文中承载的数据的类型;
    • 1, ICMP; 2 IGMP; 6 TCP; 17 UDP;
  • 校验和:
    • 16位补码;仅针对头部计算;每一条都需要重新计算;
  • 源IP地址和目的IP地址。
  • IP选项,可省略。譬如,可以在IP头部中记录路由。
    • 思考:IP选项的长度最长为多少?

下面重点讨论下IP分片。

为什么需要IP分片功能呢?主要是因为硬件环境的MTU限制。一个IP报文最多可以达到65535的最大长度;但是网络硬件限制了帧的大小(以太网限制为1500字节)。

IP fragmentation:在IP层将报文根据MTU分片;每个片段使用与IP报文同样的报头;每个片段独立地路由。

如何进行分片?

IDENT: 也即identifier,用于标识IP报文段的唯一标识符;具有同一IDENT的片段属于同一个IP报文;

FRAGMENT OFFSET: 简称FO,指明当前片段在原始完整的IP报文中的位置(偏移)。该偏移的单位是8个字节。

FLAGS: bit 0:保留;bit 1:不分片;bit 2:更多分片。如果此位是1,那么说明不是最后一个分片,如果是0,说明是最后一个分片。

  • 思考:这个指示位的功能是什么?

【因为每个分片的Total Length字段都只会指明当前的分片的长度,而不是完整报文的长度;因此接收方没办法判断报文什么时候结束;有这个指示位,可以帮助判断。】

当接收方接收到分片,应该如何进行重组呢?

在IP层上必须进行重组,将完整的数据包发到上层。

在IP协议的设计中就需要考虑一些问题:在路由器上上进行重组还是在目的主机进行重组?

如果某一个IP分片在路上因为各种原因丢失,怎么办?

如果接收到的分片在Fragment Offset上出现的重叠,怎么办?

如果重组之后大小超过65535,允许的最大值,怎么办?

针对IP分片功能,有各种攻击思路:

  1. DoS: 思路:攻击者构造两个分片,第一个分片的偏移为0;第二个分片的偏移是64800。因为IP分片可以乱序到达,所以接收方会等待其他分片;同时会为其他分片分配内存空间。相当于一个数据包会使用64K的内存。而且这段空间会持续保留15~255秒。这样,很快会耗尽主机的内存空间,造成DoS。Windows 2000, XP, 以及Unix的各版本都有这个漏洞。
  2. TearDrop。这个攻击构思很巧妙。为了理解这个攻击,我们先看一小段代码:
#include <stdio.h>
int main()
    unsigned short a=50;
    unsigned short b=30;
    unsigned short c=100;
    printf("%hu\n",a-b);
    printf("%hu\n",a-c);
    return 0;
}       

分析一下上面代码的输出是什么。

【在计算机中,负数以其正值的补码形式表达。原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。补码:反码加1称为补码。】

TearDrop攻击的原理,在于构造两个分片。其中,第二个分片完全包含在第一个分片中。也即,第二个分片的FO大于第一个分片的FO,但是第二个分片的FO+ Len,都小于第一个分片最后一个字节的位置,也即第一个分片的FO+len。

同时,这种攻击的成功,依赖于一种当分片发生重叠时,重组的方法。如果接收主机的实现中选择在发生重叠时,使用第一个分片来覆盖第二个分片的重叠内容,那么TearDrop攻击就能够成功。

if (prev != NULL && offset < prev->end)
// if there are overlapping fragments;offset是第二个分片的offset,小于前一分片的结尾,存在重叠
i = prev->end - offset;   //计算重叠的长度,保留前一分片的重叠部分
offset += i;/* ptr into datagram */   //移动到第二分片的非重叠内容,也即前一分片的结尾
ptr += i;/* ptr into fragment data */ // 指针移动到前一分片的结尾,然后拷贝第二分片的剩余内容
//advance to the end of the previous fragment
fp->len = end - offset;  // 计算接下来需要拷贝多少字节
}

以上这一段是用来计算到底重叠了多少字节(i),然后将指向第二个分片的指针朝后移动这么多字节,也即,忽略了第二个分片的重叠部分。

接下来需要将第二个分片的剩余内容拷贝一下,以形成完整的数据报文。首先需要计算第二个分片还剩余多少字节。

fp->len = end - offset;

接下来就可以从ptr开始,拷贝fp->len字节的内容,就完成了处理。对于正常的重叠,这种处理方式是完全可行的。

正常重叠


但是对于不正常的重叠,会发生什么情况呢?

不正常的重叠

【对以下内容的理解:这里主要的问题是涉及到包过滤器;包过滤器能阻止某些IP包通过路由器,可对数据包的源和目的地址作检查,也可对数据包使用的应用层协议作检查。】

RFC 1858 【1995年】

IP分片可用于伪装TCP数据包,以使其(恶意的或攻击TCP包)通过路由器和主机中的IP过滤器【包过滤防火墙】。 本文档描述了两种攻击方法,以及防止它们的措施。

  1. 背景

系统管理员依靠网络设备制造商以及数据包过滤器(filter)来维护内部网络的安全;这些过滤器用于防止攻击者访问私有系统和信息,同时允许友好代理在私有网络和Internet之间传输数据。因此,网络设备供应商必须预测可能对其设备的攻击,并实施强大的机制来防止此类攻击。

全球互联网的发展带来了“不良因素”的增加。最近几个月,在互联网主机上使用了新的攻击,这些攻击在某些情况下导致了敏感数据的泄露。

越来越复杂的攻击者开始利用互联网协议的更微妙的方面;IP数据包的碎片化是异构互联网络中的一个重要特征,它提出了我们在此探讨的几个潜在问题。

2. 过滤IP碎片

路由器上的IP数据包过滤器可以对管理员隐藏数据包碎片;在概念上,IP过滤器应用于作为完整实体的每个IP碎片。

Mogul 描述的片段过滤方法,将跟踪将过滤规则应用于第一个分片(FO == 0),并将对第一个分片的结果应用于同一个数据包的后续分片。过滤模块将维护由源地址、目的地址,协议和IP ID索引的分组列表。当看到初始(FO == 0)片段时,如果设置了MF位,则将分配列表项以保存过滤器访问检查的结果。当具有非零FO的数据包进入时,使用匹配的SA/DA/PROT /ID查找list元素并应用存储的结果(pass或block)。当看到具有零MF位的片段时,释放列表。

虽然这种方法(或它的一些改进)可能成功地删除任何有问题的整个数据包的痕迹,但它有一些问题。碎片在不同路径上路由,从而无序到达,可能会导致不期望的碎片通过过滤器。此外,如果过滤路由器位于多个并行路径中的一个,则过滤模块将不会看到每个片段,并且在应该丢弃的分组的情况下不能保证过滤完整的片段。

幸运的是,我们不需要删除有问题的数据包的所有片段。由于“有趣的”分组信息一般都在开头包含在头部中,因此过滤器通常仅需要对第一个片段设置规则。可以对非第一个片段直接通过而不用过滤,因为如果第一个片段丢失,目标主机将无法完成数据包的重组,因此将丢弃整个数据包。

Internet协议允许将数据包分成非常细小的碎片,即使这样做会导致数据和计算开销巨大而变得不切实际。攻击者有时可以利用常用的过滤器行为以及创建特殊的片段序列,以便通过过滤器从而隐藏其他不允许的数据包。在正常的实践中,从不使用这种病态的碎片,因此可以安全地丢弃这些碎片而不会妨碍正常操作。

3. 微小的碎片攻击

通过许多IP实现,可以在发出数据包上形成异常小的片段大小。如果片段大小足够小以迫使某些TCP数据包的TCP头字段进入第二个片段,则指定这些字段的模式的过滤规则将不匹配。如果过滤实现没有强制执行最小片段大小,则可能会通过不允许的数据包,因为它在过滤器中没有得到匹配。

STD 5,RFC 791规定:
每个互联网模块能够转发68个八位字节的最小数据报,不允许进一步分段。这是因为IP头部最多可达60个八位字节,从而IP数据的最小片段为8个八位字节。

注意,出于安全性的目的,仅仅保证片段包含IP头之外的至少8个八位字节的数据是不够的,因为重要的传输头信息(例如,TCP头的CODE字段)超出了第8个字节。

3.1 微小碎片攻击的例子

在此示例中,第一个片段仅包含八个字节的数据(最小片段大小)。在TCP的情况下,这足以包含源和目标端口号,但它将强制TCP标志字段进入第二个片段。

尝试删除连接请求的过滤器(具有SYN = 1和ACK = 0的TCP数据报)将无法在第一个八位字节中测试这些标志,并且通常会在后续片段中忽略它们。

FRAGMENT 1
      IP HEADER
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      |     | ... | Fragment Offset = 0 | ... |     |
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      TCP HEADER
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |        Source Port            |       Destination Port        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                       Sequence Number                         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
FRAGMENT 2
      IP HEADER
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      |     | ... | Fragment Offset = 1 | ... |     |
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      TCP HEADER
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                    Acknowledgment Number                      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Data |           |U|A|P|R|S|F|                               |
      | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
      |       |           |G|K|H|T|N|N|                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

3.2 防止微小碎片攻击

在路由器中,可以通过对通过的片段强制执行某些限制来防止这种类型的攻击,即第一个片段足够大以包含所有必需的头信息。

有两种方法可以保证“通过”的数据包的第一个片段包含所有必需字段,一个是直接的,另一个是间接的。

3.2.1 直接法

设置下限TMIN,它是包含“有趣”字段所需的传输头的最小长度(即,其值对于包过滤器而言是重要的字段)。该长度是从原始未分段IP分组中的传输头的开头开始测量的。

请注意,TMIN是所涉及的传输协议以及当前配置的特定过滤器的函数。

直接方法涉及计算每个零偏移片段中传输头的长度,并将其与TMIN进行比较。如果传输头长度小于TMIN,则丢弃该片段。不需要检查非零偏移片段,因为如果丢弃零偏移片段,则目标主机将无法完成重组。到目前为止,我们有:

 if FO==0 and TRANSPORTLEN < tmin then
                    DROP PACKET

不过,除了TCP之外,其他传输协议的“有趣”字段位于传输头的前八个八位字节中,因此不可能将它们推入非零偏移片段。因此,在撰写本文时,只有TCP数据包容易受到微小碎片攻击,并且不需要对其他传输协议的IP数据包进行测试。因此,微小片段测试的更好版本可能是:

            如果FO = 0且PROTOCOL = TCP,则TRANSPORTLEN <tmin
                    DROP PACKET

但是,正如下面关于重叠片段的部分所讨论的,此测试不会阻止所有碎片攻击,并且在使用更通用的技术时实际上是不必要的。

3.2.2 间接方法

间接方法依赖于这样的观察:当TCP数据包被分段以便迫使零偏移片段(第一个分片)中不存在“有趣”的头部字段时,必定存在FO等于1的片段。

如果看到具有FO == 1的分组,则相反地,它可以指示在片段集中存在具有八个八位字节的传输报头长度的零偏移片段。丢弃该FO == 1偏移片段将阻止接收主机对数据报文的重组,并且与上述直接方法一样有效。

4. 重叠碎片攻击

RFC 791(当前的IP协议规范)描述了一种重组算法,该算法导致新的片段覆盖先前接收的片段的任何重叠部分。

给定这样的重组实现,攻击者可以构造一系列数据包,其中,最低(零偏移)片段将包含无害数据(从而通过管理数据包过滤器传递),并且其中一些后续数据包具有非零offset会重叠TCP头信息(例如目标端口)并导致它被修改。第二个数据包将被通过大多数的过滤器通过,因为它没有零片段偏移量。

RFC 815概述了一种改进的数据报重组算法,但它主要涉及在重组过程中填补空白。这个RFC在重叠片段问题上仍然没有帮助。

因此,完全兼容的IP实现不能保证不受重叠片段攻击的影响。 4.3 BSD重组实现通过强制使用较低偏移的数据来覆盖较高偏移的数据来避免这些攻击。但是,并非所有IP实现都基于原始BSD代码,并且很可能其中一些是易受攻击的。

4.1 重叠片段攻击的示例

在此示例中,片段足够大以满足上一节中描述的大小要求。过滤器配置为丢弃TCP连接请求数据包。

第一个片段包含值,例如,SYN = 0,ACK = 1,使其能够无损地通过过滤器。

具有八个八位字节的片段偏移的第二片段包含与第一片段中给出的TCP标志不同的TCP标志,例如,SYN = 1,ACK = 0。由于该第二个片段不是0偏移片段,因此不会检查它,并且它也将通过过滤器。

如果接收主机完全符合RFC 791中给出的算法,它将重新组合数据包作为连接请求,因为“坏”数据后面才到达。

FRAGMENT 1
      IP HEADER
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      |     | ... | Fragment Offset = 0 | ... |     |
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      TCP HEADER
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |        Source Port            |       Destination Port        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                       Sequence Number                         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                    Acknowledgment Number                      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Data |           |U|A|P|R|S|F|                               |
      | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
      |       |           |G|K|H|T|N|N|                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                        (Other data)                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      FRAGMENT 2
      IP HEADER
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      |     | ... | Fragment Offset = 1 | ... |     |
      +-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+
      TCP HEADER
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                    Acknowledgment Number                      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Data |           |U|A|P|R|S|F|                               |
      | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
      |       |           |G|K|H|T|N|N|                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                        (Other data)                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

如果接收主机具有阻止新数据覆盖先前接收的数据的重组算法,我们可以首先发送片段2,然后发送片段1,并完成相同的成功攻击。

4.2 防止重叠碎片攻击

由于没有标准要求使用重叠安全的重组算法,因此主机对此攻击的潜在漏洞非常大。

在路由器的IP过滤代码中采用更好的策略,可以确保阻止这种“攻击”。如果路由器的过滤模块对具有非零偏移的片段强制执行最小片段偏移,则可以防止传输包头的过滤器参数区域中出现重叠。

在TCP的情况下,该最小值是十六个八位字节,以确保TCP标志字段永远不包含在非零偏移片段中。如果TCP片段的FO == 1,则应该将其丢弃,因为它只在传输头中开始八个八位字节。方便地,丢弃FO == 1片段也可以防止微小片段攻击,如前所述。

RFC 791要求IP协议栈必须能够传递8字节IP数据有效载荷没有进一步的碎片(片段位于8字节边界)。由于IP头最长可达60个字节(包括选项),这意味着链路上的最小MTU应为68字节。

典型的IP报头只有20个字节长,因此可以携带48个字节的数据。在现实世界中,没有人应该生成FO == 1的TCP数据包,因为它需要先前的系统将IP数据分段为最小8字节和60字节IP头。

因此,一种通用算法,用于确保过滤器在微小片段攻击和重叠片段攻击面前工作的是:

 如果FO == 1 并且 PROTOCOL == TCP
                 DROP PACKET

如果在路由器中提供基于其他传输协议头中的字段的过滤,则最小值可能更大,具体取决于头中这些字段的位置。特别是,如果允许对传输头的第十六个八位字节以外的数据进行过滤,则由于灵活的用户界面或某些新传输协议的过滤器的实现,丢弃具有FO == 1的数据包可能是不够的。




RFC 3128

1.简介

RFC 1858提供了对Internet防火墙的一类攻击的出色描述,并提出了对策。 然而,这些计量措施之一,“间接方法”(第3.2.2节)容易受到所描述的两种攻击的组合。

该攻击结合了“微小碎片攻击”(第3节)和“重叠碎片攻击”(第4节)的特征。

1.1 攻击范围

如果过滤规则允许到机器的传入连接,并且其他端口只允许同一主机上的传出连接,则攻击允许传入连接到所谓的仅传出端口。

请注意,只需要对初始连接消息进行分段。 一旦建立连接,其上的进一步流量是合法的。 这种弱点的重要性将取决于现行的安全政策。

2. 微小的重叠片段攻击

攻击通常包括发送三个片段。

片段1 : (片段偏移 = 0;长度> = 16)包括整个标头并且完全合法。通常,它描述了一个SYN数据包,它启动新TCP连接到允许接收传入连接的目标主机上的端口。例如,到端口25 的SMTP的传入连接。

片段2 : (片段偏移 = 0;长度= 8)只有前8个字节,并且具体取决于标头的其他8个字节可能是合法的,但是当与片段1中的相应字节组合之后,会不合法。这样的片段仅包括TCP标头中的端口号和序列号。通常,此数据包使用端口号替换目标端口号,在该端口号上不允许接收传入连接的目标主机。

片段3 :(片段偏移 > = 2;长度=消息的其余部分)不包含标头并完成消息。 (第三个片段不是攻击的一部分。但是,片段1不能是完整的消息,否则它会在片段2到达之前传递给应用程序,因此需要第三个片段。)

2.1攻击示例

考虑以下一组简单的传入数据包规则:

 +---+-------+-------+-------+-------+-----------------------+
   | No|Action | Source| Dest. | Flags | Purpose               |
   |   |       | Port  | Port  |       |                       |
   +===+=======+=======+=======+=======+=======================+
   | 1 |Permit | >1023 | SMTP  |  ANY  | Incoming E-mail       |
   +---+-------+-------+-------+-------+-----------------------+