链路层具有最大传输单元MTU 这个特性,它限制了数据帧的最大长度,不同
的网络类型都有一个上限值。以太网的MTU 是1500,你可以用 netstat -i 命
令查看这个值。如果IP层有数据包要传,而且数据包的长度超过了MTU,那
么IP 层就要对数据包进行分片(fragmentation)操作,使每一片的长度都小
于或等于MTU。
我们假设要传输一个UDP 数据包,以太网的MTU 为1500字节,一般IP首部
为20 字节,UDP 首部为8 字节,数据的净荷(payload)部分预留是
1500-20-8=1472字节。如果数据部分大于1472 字节,就会出现分片现象。
IP 首部包含了分片和重组所需的信息:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |R|DF|MF| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|<-------------16------------->|<----3--->|<------------------13----------------->|
Identification:发送端发送的IP 数据包标识字段都是一个唯一值,该值在分片
时被复制到每个片中。
R:保留未用。
DF:Don't Fragment,“不分片”位,如果将这一比特置1 ,IP层将不对数据
报进行分片。
MF:More Fragment,“更多的片”,除了最后一片外,其他每个组成数据报的
片都要把该比特置1。
Fragment Offset:该片偏移原始数据包开始处的位置。偏移的字节数是该值乘
以8。
另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。
每一IP 分片都各自路由,到达目的主机后在IP 层重组,请放心,首部中的数
据能够正确完成分片的重组。你不禁要问,既然分片可以被重组,那么所谓的
碎片攻击是如何产生的呢?
IP 首部有两个字节表示整个IP 数据包的长度,所以IP 数据包最长只能为
0xFFFF,就是65535 字节。如果有意发送总长度超过65535 的IP碎片,一些
老的系统内核在处理的时候就会出现问题,导致崩溃或者拒绝服务。另外,如
果分片之间偏移量经过精心构造,一些系统就无法处理,导致死机。
jolt2.c 是在一个死循环中不停的发送一个ICMP/UDP 的IP 碎片,可以使
Windows 系统的机器死锁。我测试了没打SP 的Windows 2000,CPU 利用率
会立即上升到100%,鼠标无法移动。
我们用Snort分别抓取采用ICMP和UDP协议发送的数据包。
发送的ICMP 包:
01/07-15:33:26.974096 192.168.0.9 -> 192.168.0.1
ICMP TTL:255 TOS:0x0 ID:1109 IpLen:20 DgmLen:29
Frag Offset: 0x1FFE Frag Size: 0x9
08 00 00 00 00 00 00 00 00 .........
发送的UDP 包:
01/10-14:21:00.298282 192.168.0.9 -> 192.168.0.1
UDP TTL:255 TOS:0x0 ID:1109 IpLen:20 DgmLen:29
Frag Offset: 0x1FFE Frag Size: 0x9
04 D3 04 D2 00 09 00 00 61 ........a
从上面的结果可以看出:
* 分片标志位MF=0,说明是最后一个分片。
* 偏移量为0x1FFE,计算重组后的长度为 (0x1FFE * 8) + 29 = 65549 > 65535,
溢出。
* IP包的ID 为1109,可以作为IDS检测的一个特征。
* ICMP包:
类型为8、代码为0,是Echo Request;
校验和为0x0000,程序没有计算校验,所以确切的说这个ICMP包是非法的。
* UDP 包:
目的端口由用户在命令参数中指定;
源端口是目的端口和1235进行OR的结果;
校验和为0x0000,和ICMP的一样,没有计算,非法的UDP。
净荷部分只有一个字符'a'。