IP协议安全

从IP协议安全开始

IP数据包

IP协议 IP包在网络层
不保证可靠性 数据包可能重复、丢失,是无连接协议
首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层。   
其中以太网(Ethernet)的数据帧在链路层 Frame是链路层的基本单元,包含链路层的头部信息(mac地址)和网络层的packet
IP包在网络层 基本单元为IP Datagrame/Packet
一个datagrame由IP Header和IP data组成

TCP或UDP包在传输层  Segment
TCP或UDP中的数据(Data)在应用层   
它们的关系是 数据帧{IP包{TCP或UDP包{Data}}}  
数据封装的过程data=>segment=>packet=>frame,同样也是层层包含的关系,可以从Wireshark中查看详细的封包情况

IP分片

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

-如何进行分片?
-IDENT: 也即identifier,用于标识IP报文段的唯一标识符;具有同一IDENT的片段属于同一个IP报文
FRAGMENT OFFSET: 简称FO,指明当前片段在原始完整的IP报文中的位置(偏移)。该偏移的单位是8个字节
FLAGS: bit 0:保留;bit 1:不分片;bit 2:更多分片。如果此位是1,那么说明不是最后一个分片,如果是0,说明是最后一个分片。
ip数据头中的3位标识最低位为mf,为1时说明这个ip数据包是分片的,并且后续还有数据包,为0时说明这个ip数据包是分片的,但已经是最后一个数据了。中间位为df,df为1时,说明这个数据包是不分片的,为零时才允许数据包分片。
-当接收方接收到分片,应该如何进行重组呢?
在IP层上必须进行重组,将完整的数据包发到上层。

在IP协议的设计中就需要考虑一些问题:
在路由器上上进行重组还是在目的主机进行重组?
如果某一个IP分片在路上因为各种原因丢失,怎么办?

尽管IP分片过程看起来是透明的,但是有一点让人不想使用它:
即使只丢失一片数据也要重传整个数据报。因为IP层本身没有超时重传机制-------由更高层来负责超时和重传(TCP有超时重传,但UDP没有。一些UDP应用程序本身也执行超时和重传),当来自TCP报文段的某一片丢失后,TCP在超时后会重发整个TCP报文段,该报文段对应于一份IP数据报,没有办法只重传数据报中的一个数据报片。事实上,如果对数据报分片的是中间路由器,而不是起始端系统,那么起始端系统就1无法知道数据报是如何被分片的。就这个原因,经常要避免分片。

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

看看程序对“fragment offset”做了那些处理:
if (prev != NULL&& offset
{
I =prev->end ?Coffset;
Offset +=I : /*ptr into datagram */
Ptr += I /* ptr into fragment data */
}
如果我们发现当前包的段偏移在前一包数据内部,也就是说根据偏移字段的值,前后两数据包的数据部分有重叠。组装程序试图正确对齐它们的边界。程序代码如上所示。这一步是对的。除非当前包中的有效数据碰巧没有足够的数据来满足对齐的要求。在这种情况下,“offset”域中的值将会比“ end”域中的值大。这两个数值被交给“ip-frag-create()”模块,在这个模块中,将会计算当前包的长度。
/* Fill in the structure. */
fp->offset =offset;
fp->end =end;
fp->len =end ?Coffset;
在这种极少见的情况下,计算出来的fp-len竟变成了一个负数,于是memcpy()最终将会把大量的数据拷贝到内核中,因为memcpy()中的记数器是一个反码,是一个非常大的数值。根据使用的内存管理机制的不同,将会引起系统重启动或停机。 

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

重新组合而成的IP数据包长度由各个IP分段的数据长度累加而成。IP头中的数据包长度域只有16位,这就限制了IP包的长度最大为65535。如果到来的IP分段的累加长度大于65535,而IP又没有进行检查,IP会因溢出而处于崩溃或不能继续提供服务的状态。

IP分片攻击

参考https://blog.csdn.net/TKE_yinian/article/details/104909830

DOS思路

攻击者构造两个分片,第一个分片的偏移为0;第二个分片的偏移是64800。因为IP分片可以乱序到达,所以接收方会等待其他分片;同时会为其他分片分配内存空间。相当于一个数据包会使用64K的内存。而且这段空间会持续保留15~255秒。这样,很快会耗尽主机的内存空间,造成DoS。Windows 2000, XP, 以及Unix的各版本都有这个漏洞。

TearDrop

最开始使用的工具叫teardrop

#include <stdio.h>
int main()
{
    unsigned short a=50;
    unsigned short b=30;
    unsigned short c=100;
    printf("%hu\n",a-b);//20
    printf("%hu\n",a-c);//65486
    return 0;
}

TearDrop攻击的原理,在于构造两个分片。其中,第二个分片完全包含在第一个分片中。也即,第二个分片的FO大于第一个分片的FO,但是第二个分片的FO+ Len,都小于第一个分片最后一个字节的位置,也即第一个分片的FO+len。
同时,这种攻击的成功,依赖于一种当分片发生重叠时,重组的方法。如果接收主机的实现中选择在发生重叠时,使用第一个分片来覆盖第二个分片的重叠内容,那么TearDrop攻击就能够成功。
当重叠时:
计算到底重叠了多少字节(i),然后将指向第二个分片的指针朝后移动这么多字节,也即,忽略了第二个分片的重叠部分。

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;  // 计算接下来需要拷贝多少字节

}

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

fp->len = end - offset;

正常重叠

不正常重叠

结果:
计算出来的fp-len竟变成了一个负数,于是memcpy()最终将会把大量的数据拷贝到内核中,因为memcpy()中的记数器是一个反码,是一个非常大的数值。根据使用的内存管理机制的不同,将会引起系统重启动或停机。

微小碎片攻击

某些机器为了阻止外部机器尝试与其连接,会在防火墙中设置过滤SYN包。因为机器如果未建立TCP连接的情况下收到别的包会自动RST。因此检查TCP第一个包的SYN位并过滤理论上可以阻断外部机器尝试与其进行连接(即FO==0且SYN ==1)。然而IP分片的设定却可以绕过这道防火墙设定。

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

我们从这篇规定看到,最小的模块为68字节,而IP头部最大可达60字节,这就意味着我们的TCP报头只要包含8个字节就可以了。这也就意味着,我们可以在第一个包里不包含我们的SYN位,而在第二包里包含。这样进入机器后被重组就又可以与目标机器建立连接了。

IP数据报最小分片长度为68字节,利用i选项字段填满ip头=60字节,则第一分片数据部分可以只有8字节
第一分片只包含tcp头的前8字节,而syn被放在了第二分片,从而避开了filter。此时第二分片的offset为1。

如何防御:
如果第二分片offset ==1 且是tcp协议,则丢弃第二分片

重叠碎片攻击

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

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

posted @ 2020-07-02 14:43  歇马  阅读(807)  评论(0编辑  收藏  举报