首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第39期->技术专题
期刊号: 类型: 关键词:
LINUX2.2.x中ICMP协议的地址伪装

作者:droplet@163.net
出处:http://www.nsfocus.com
日期:2003-03-03

1. 概述

ICMP协议有两种类型: 查询报文和差错报文.其格式如下:

[图1.1]
查询报文中,Type是查询类型;Code值为0没有使用;Checksum是ICMP头和数据的校验和;Identifier用于标识发包的session,一般填为进程的Id;Sequence标识同一session中的不同包,序列号每次加1;Data中的数据因Type的不同而不同.地址伪装中处理的查询报文类型以及其应答报文的类型为:

ICMP_ECHO,ICMP_ECHOREPLY;
ICMP_TIMESTAMP,ICMP_TIMESTAMPREPLY;
ICMP_INFO_REQUEST,ICMP_INFO_REPLY;
ICMP_ADDRESS,ICMP_ADDRESSREPLY.


[图1.2]
差错报文中,Type是差错类型;Code是差错类型中的子类型;Checksum是ICMP头和数据的校验和.其数据部分包含出错包的IP头(包括选项)和IP数据的前八个字节.地址伪装只处理三种协议(ICMP,TCP,UDP)的差错包,并且只处理三种类型的差错报文,如下:

ICMP_DEST_UNREACH,ICMP_SOURCE_QUENCH,ICMP_TIME_EXCEEDED.

2. ICMP协议的地址伪装

下面分析伪装和解伪装两个过程对ICMP包的处理,并引用下图所示的环境进行分析:

[图2.1]
在FW上配置A到B的地址伪装,B到A的端口转发规则如下:
ipchains –A forward –s 10.0.0.0/8 –d 192.168.0.0/24  -j MASQ
ipmasqadm portfw –a –L  192.168.0.88 –R 10.0.0.1
分析所涉及的几个不同的情形是:

(1)    A到B的ICMP查询报文,B返回成功的应答报文.
(2)    A到B的ICMP查询报文,B返回失败的差错报文.
(3)    A到B的TCP或UDP请求,B返回失败的差错报文.
(4)    B到A的ICMP查询报文,这种情况没有处理.
(5)    B到A的TCP或UDP请求,A返回失败的差错报文.

2.1. ip_fw_masquerade

ip_fw_masquerade处理A到B的查询报文和差错报文.首先在ip_fw_masquerade中判断协议类型是否是ICMP,如果是,则调用函数ip_fw_masq_icmp.在这个函数中,对查询报文和差错报文的处理过程不同,下面分两种情况讨论.

2.1.1. 查询报文

a: 判断ICMP的类型是否是查询报文类型:
ICMP_ECHO,ICMP_TIMESTAMP,ICMP_INFO_REQUEST,
ICMP_ADDRESS.如果不是,跳过下面的处理.如果是,到下一步.
b: 在伪装结构的哈希表中查找相应的伪装结构是否已创建(ip_masq_out_get),查找时用icmp_id(查询报文中的Identifier)代替源端口;用icmp_hv_req(查询报文中的Code加Type左移八位)代替目的端口.如果查找不成功,创建新的伪装结构,如图:

[图2.2]
c: 将IP头中的源地址替换为伪装地址: iph->saddr = ms->maddr.ICMP头中的Identifier替换为伪装端口:(icmph->un).echo.id = ms->mport.以上两步需要重新计算IP头和ICMP头和数据的校验和.

2.1.2. 差错报文

对差错报文的处理可以分为两类来讨论.第一类是ICMP查询报文的差错报文(差错报文不会产生新的差错报文,否则会造成死循环);第二类是TCP/UDP的差错报文.在处理之前首先判断差错报文的类型是否是系统可以处理的类型:
ICMP_DEST_UNREACH,ICMP_SOURCE_QUENCH,ICMP_TIME_EXCEEDED. 如果不是,直接返回0.

2.1.2.1. ICMP的差错报文

a: 找到差错报文中包含的原IP头,查看其协议是否是ICMP,如果不是,跳过下一步的处理.
b: 在伪装结构的哈希表中查找是否有差错报文中原查询报文对应的伪装结构(这个结构应该在ip_fw_demasquerade中创建). 这里查找所使用的地址是原查询报文的地址,所以源地址/目的地址与正常的查找是相反的.如果没有找到相应的结构,返回0.
c: 然后修改IP头中的源地址:iph->saddr = ms->maddr;
原IP头中的目的地址: ciph->daddr = ms->maddr;
和原查询报文中的Identifier: (cicmph->un).echo.id = ms->mport. 以上的修改要重新计算IP头和ICMP头和数据的校验和.

2.1.2.2. TCP/UDP的差错报文

a: 找到差错报文中包含的原IP头,查看协议是否是TCP或UDP,如果不是,返回0.
b: 在伪装结构的哈希表中查找是否有与差错报文中的原TCP或UDP包对应的伪装结构(这个结构应该在ip_fw_demasquerade中创建). 这里查找所使用的地址和端口是原TCP或UDP包中的地址和端口,所以源地址/源端口和目的地址/目的端口与正常的查找是相反的.如果没有找到相应的结构,返回0.
c: 然后修改IP头中的源地址:iph->saddr = ms->maddr;
原TCP或UDP包中的目的地址和目的端口:
ciph->daddr = ms->maddr; pptr[1] = ms->mport. 以上的修改要重新计算IP头和ICMP头和数据的校验和.

2.2. ip_fw_demasquerade

ip_fw_demasquerade处理B到A查询报文和差错报文.对ip_fw_demasquerade的分析也采用与分析ip_fw_masquerade相同的分类来进行.首先在ip_fw_demasquerade中判断协议类型是否是ICMP,如果是,则调用ip_fw_demasq_icmp来处理.

2.2.1. 查询报文

a: 首先判断查询报文的类型是否是系统可以处理的类型: ICMP_ECHOREPLY,ICMP_TIMESTAMPREPLY,ICMP_INFO_REPLY, ICMP_ADDRESSREPLY(这里的类型都是查询报文的应答报文,所以必须先有A到B的查询报文.默认不处理B到A的查询报文).如果不是,跳过后面的处理.如果是,到下一步.
b: 在伪装结构的哈希表中查找相应的伪装结构是否已创建(这个结构应该在ip_fw_masquerade中处理A到B的查询报文时创建). 查找使用icmp_hv_rep得出的值代替源端口,用icmp_id得出的值代替目的端口.
c: 然后拷贝SKB中的数据(在这之前使用的是SKB指针,如果这是一个clone的指针,说明数据被共享,改动之前,应先复制一份新的数据,后面也有相同的问题).
d: 将IP头中的目的地址替换为伪装结构中的源地址:iph->daddr = ms->saddr; 将ICMP头中的Identifier替换为伪装结构中的源端口:(icmph->un).echo.id = ms->sport. 以上的修改需要重新计算IP头和ICMP头和数据的校验和.

2.2.2. 差错报文

差错报文同样分为ICMP查询报文的差错报文和TCP或UDP的差错报文两种情况讨论.处理之前先要判断差错报文的类型是否是系统可以处理的三种类型:
ICMP_DEST_UNREACH,ICMP_SOURCE_QUENCH,ICMP_TIME_EXCEEDED.如果不是,返回0.

2.2.2.1. ICMP的差错报文

a: 首先判断原IP头中的协议号是否是ICMP.如果不是,跳过下面的处理.
b: 在伪装结构的哈希表中查找与原ICMP包对应的伪装结构(这应该在ip_fw_masquerade中创建)是否存在.查找使用的是原ICMP包中的地址,所以源地址和目的地址与正常的查找相反.如果没有找到这个结构,则返回0.
c: 拷贝SKB的数据(masq_skb_cow).
d: 修改IP头中的目的地址: iph->daddr = ms->saddr;
原ICMP头中的源地址和Identifier:
ciph->saddr = ms->saddr; (cicmph->un).echo.id = ms->sport.以上的修改需要重新计算IP头和ICMP头和数据的校验和.

2.2.2.2. TCP/UDP的差错报文

a: 首先判断原IP头中的协议号是否是TCP或UDP,如果不是,返回0.
b: 在伪装结构的哈希表中查找与原TCP或UDP包对应的伪装结构(这应该在ip_fw_masquerade中创建)是否存在.查找使用的是原TCP或UDP包中的地址和端口.所以源地址/源端口,目的地址/目的端口与正常的查找相反.如果没有找到这个结构.则返回0.
c: 拷贝SKB的数据(masq_skb_cow).
d: 修改IP头中的目的地址: iph->daddr = ms->saddr;
原TCP或UDP包中的源地址/源端口:
ciph->saddr = ms->saddr;pptr[0] = ms->sport.以上的修改需要重新计算IP头和ICMP头和数据的校验和.

2.3. 总结

地址伪装修改转发包的地址(源地址或目的地址)和端口(源端口或目的端口). ICMP协议中没有端口的概念,所以使用了一些特殊的处理方法.从上面的分析可以看到.默认情况下,只处理OUTBOUND(内到外)方向上的查询报文,INBOUND(外到内)方向上只处理OUTBOUND查询报文的应答报文.差错报文在两个方向上都处理.
版权所有,未经许可,不得转载