原创 | Ripple20:Treck TCP/IP协议栈误差剖析与验证
宣布时间 2020-06-30一、前言
外洋清静研究职员在由Treck开发的TCP/IP协议栈中发明了多个误差,这一系列误差统称为Ripple20。这些误差普遍保存于嵌入式和物联网装备中,影响了多个行业领域(包括医疗、运输、能源、电信、工业控制、零售和商业等),涉及了众多供应商(包括HP、Schneider Electric、Intel、Rockwell Automation、Caterpillar、Baxter等)。
这些误差源于Ripple20的多个协议(包括IPv4、ICMPv4、IPv6、IPv6OverIPv4、TCP、UDP、ARP、DHCP、DNS或以太网链路层)在处置惩罚网络报文发送时保存缺陷,其中包括四个严重误差,它们的CVE编号划分为CVE-2020-11896、CVE-2020-11898、CVE-2020-11910、CVE-2020-11911。CVE-2020-11896(CVSS评分10)可导致远程执行代码,CVE-2020-11897(CVSS评分10)可导致越界写入,CVE-2020-11901(CVSS评分9)可导致远程执行代码,CVE-2020-11898(CVSS评分9.1)可导致泄露敏感信息。其它15个Ripple20误差的严重水平各异,CVSS评分划分从3.1到8.2。
由于物联网装备供应链的特征,误差影响的装备众多,影响规模广且一连时间长,误差修复的实验较难题。因此,尊龙凯官网入口ADLab第一时间对相关误差举行了剖析并提出了提防建议。
二、协议栈检测
由于接纳Treck协议栈的厂家较多,有些厂家是硬件IP核的方法引用了Treck协议栈。纯粹通过装备指纹来识别误差是缺乏的,怎样检测目的装备是否为Treck协议栈成为资产排查的要害,为此尊龙凯官网入口ADLab清静研究员对Treck协议栈举行了深入剖析,并果真了Treck协议栈指纹检测要领发明误差。
Treck协议栈自界说了类型为165(0xa5)的ICMP包,并一旦收到165的ICMP包会回复类型为166的ICMP包响应。如下代码所示:
首先,向目的发送 ICMP请求包,其中type=0xa5,code=0。如下图所示:
然后,吸收目的返回的icmp响应包数据,其中type =0xa6,code =0,ICMP报文第9字节后的六个字节为0x01,0x51,0x35,0x28,0x57,0x32(大端)或0x51,0x01,0x28,0x35,0x32,0x57(小端)。
知足上述的条件,则批注目的装备为treck 协议栈。如下图所示:
三、提防建议
1、应用更新
实时更新到Treck TCP/IP协议栈软件的最新稳固版本(6.0.1.67或更高版本)。
2. 阻止异常IP流量
可以通过深度数据包检查来阻止网络攻击,以下是可以适当应用于网络情形中的可能缓解步伐,过滤选项包括:
● 若是网络情形不支持,则规范化或拒绝IP分片的数据包(IP分片)
● 若是不需要,请禁用或阻止IP隧道(IPv6-in-IPv4或IP-in-IP隧道)
● 阻止IP源路由和所有不赞成使用IPv6的功效,例如路由标头
● 强制执行TCP检查并拒绝名堂过失的TCP数据包
● 阻止未使用的ICMP控制新闻,例如MTU更新和地址掩码更新
● 通过清静的递归服务器或应用层防火墙规范DNS
● 确保网络情形中使用的是可靠的OSI第2层装备(以太网)
● 通过DHCP侦听等功效提供DHCP / DHCPv6清静性
● 若是未在交流基础架构中使用,则禁用或阻止IPv6多播。
四、相关看法先容
1、IP分片
IP分片使得在网络中发送大的IP包成为可能,纵然其巨细大于网络特定链路中允许的最大值。IP分片手艺是一种将数据包分成几个较小的部分以支持通过这些链路和网络传输的手艺。该协议支持在发送端举行分片,然后在吸收端对分片重新组合。这允许差别的包在网络中零星地传输,并在另一侧准确地重新组装。
差别的包使用IP头中的标识字段(Identification)举行分组。此标识字段形貌分片属于哪个包。统一个包的多个分片的Identification是一样的。IPv4通过Flags及Fragment Offset字段对分片举行管理,Flags由R、DF、MF三部分组成:
● R(Reserve bit)保存未用
● DF (Don't Fragment) DF =1:榨取分片 , DF =0:允许分片
● MF (More Fragment) MF =1:非最后一片, MF =0:最后一片(或未分片)
Fragment Offset(13位):一个IP分组分片封装原IP分组数据的相对偏移量, 片偏移字段以8字节为单位。IP包结构如下图所示:
2、IP隧道手艺
IP隧道允许两个自力网络之间的虚拟点到点链路。它是通过将包(可以是IP包)封装在另一个包中来实现的,使得内部包具有与外部包差别的源地址和目的地址。外部包的源地址和目的地址是隧道端点,内部包中的地址用于隧道两头的网络路由。隧道入口点是吸收应通过隧道转发的IP数据包的节点。它将此数据包封装在外部IP数据包中。当数据包抵达隧道出口点时,它被解封装并转发,就似乎它是在目的网络中发送的通例数据包一样。IP-in-IP包如下图所示:
IP隧道手艺主要应用在虚拟专用网(VPN)手艺中。现在有几种隧道协议,其中最简朴和最古老的是IP-in-IP(IP协议编号4)。IP-in-IP是一种IP隧道协议,其中一个IP包通过添加一个外部IP报头(其源地址和目的地址划分即是隧道的入口点和出口点)封装在另一个IP包中。内部数据包未被修改,外部IP头从内部IP头复制一些字段。外部报头的IP协议号为4。IP-in-IP报文示例如下图所示:
五、Treck协议栈
1、协议栈概述
Treck协议栈通过tsPacket结构来形貌包结构,通过tsUserPacket结构支持数据包分片。这两个结构体在treck/include/trsocket.h文件中界说。Treck TCP/IP协议栈中的包数据由tsPacket的结构体现。每个包都与一个数据缓冲区相关联,该数据缓冲区生涯从接口驱动程序抵达的原始数据。tsPacket结构还生涯另一个称为ttUserPacket的主要结构,以及指向tsSharedData结构的指针,该结构包括网络协议栈处置惩罚数据包时所需的信息(指向套接字结构、src/dst地址或端口等的指针)。界说如下:
struct tsPacket {
ttUserPacket pktUserStruct;
ttSharedDataPtr pktSharedDataPtr;
struct tsPacket * pktChainNextPtr;
struct tsDeviceEntry * pktDeviceEntryPtr;
union anon_union_for_pktPtrUnion pktPtrUnion;
tt32Bit pktTcpXmitTime;
tt16Bit pktUserFlags;
tt16Bit pktFlags;
tt16Bit pktFlags2;
tt16Bit pktMhomeIndex;
tt8Bit pktTunnelCount;
tt8Bit pktIpHdrLen;
tt8Bit pktNetworkLayer;
tt8Bit pktFiller[1];
};
这是包括的ttUserPacket结构(tsUserPacket的typedef),界说如下:
struct tsUserPacket {
void * pktuLinkNextPtr; // Next tsUserPacket for fragmented data
ttUser8BitPtr pktuLinkDataPtr;
ttPktLen pktuLinkDataLength;
ttPktLen pktuChainDataLength;
int pktuLinkExtraCount;
};
pktuLinkNextPtr :用于跟踪数据包中的分片。此字段指向体现下一个分片的另一个tsPacket结构,该tsPacket还生涯对下一个分片的引用,若是此链接是最后一个分片,或者数据未被分片,则此字段将为NULL。
pktuLinkDataPtr:指向目今分片的数据缓冲区。当Treck协议栈在差别阶段处置惩罚数据包时,数据缓冲区中简直切位置会爆发转变,这取决于目今正在处置惩罚的数据包所在协议层。例如,当Treck协议栈处置惩罚以太网层(在tfEtherRecv()函数中)时,此字段指向以太网报头。
pktuLinkDataLength:pktuLinkDataPtr指向的数据的巨细,即单个分片的巨细。
pktuChainDataLength:体现包括所有分片的数据包长度,即数据包的总巨细。它只为第一个分片设置。若是数据没有分片,则即是pktuLinkDataLength。
2、协议栈处置惩罚历程
协议栈中的一个常见模式是在协议栈中的层之间移动时调解pktuLinkDataPtr指针。例如,若是我们的包是一个ICMP回显请求包(ping),它的协议由三层组成:Ethernet、IPv4、ICMP。在这种情形下,当处置惩罚以太网层(在tfEtherRecv()函数中)时,pktuLinkDataPtr指向以太网报头的最先,然后在移动到下一层之前,使用以下代码对其举行调解,如下代码所示:
在本例中,0xe(十进制为14)是以太网报头(6(dst MAC)+6(src MAC)+2(etherType))的巨细。当tfEtherRecv()函数完成包处置惩罚时,它将包转发到下一层处置惩罚。支持的以太网类型有ARP、IPv4和IPv6。如下代码所示:
在示例中,当IPv4层吸收到数据包(在函数tfIpIncomingPacket()函数中)时,指针pktuLinkDataPtr已经指向IP报头。传入数据由具有相同命名约定tf*IncomingPacket的函数处置惩罚,其中*是协议名。关于ICMP包来说,它由三层协议组成(Ethernet/IPv4/ICMP),数据包将由函数tfEtherRecv、tfIpIncomingPacket和tfIcmpIncomingPacket函数划分处置惩罚。
3、分片重组
Treck协议栈在tfIpReassemblePacket()函数中处置惩罚分片的重组,该函数由tfIpIncomingPacket()挪用。每当吸收到发往装备的IP分片时,就会挪用此函数。若是缺少分片,函数将返回NULL。不然,若是所有分片都抵达并且没有朴陋,则网络协议栈将使用pktuLinkNextPtr字段将分片链接在一起,然后将数据包转达给下一层举行进一步处置惩罚。在此上下文中,“重组”一词并不料味着将数据包复制到一连的存储块,而只是简朴地将它们链接到一个链表中。分片数据链表结构如下图所示:
4、tfIpIncomingPacket函数
tfIpIncomingPacket()函数是处置惩罚IP包的主要函数,该函数主要流程如下图所示:
tfIpIncomingPacket()首先判断数据包正当性。tfIpIncomingPacket()函数除了验证IP头校验和,它还举行以下验证,如下代码所示:
然后若是所有正当性检查都通过,tfIpIncomingPacket()函数将检查IP报头中TotalLength 是否严酷小于数据包的pktuChainDataLength,这体现现实吸收的数据比IP报头中声明的数据多。若是是真的,则举行修剪操作,要删除特另外数据,如下代码所示:
再者若是IP数据包的MF为1或者Fragment Offset大于0,则tfIpIncomingPacket()函数就要挪用tfIpReassemblePacket()函数举行分片重组。若是IP分片数据吸收不完整,则tfIpReassemblePacket()函数返回NULL。若是所有IP分片都抵达并且没有过失,则Treck协议栈使用pktuLinkNextPtr字段将这些分片链接在一起,建设链表,并将包转达到下一层举行进一步处置惩罚,如下代码所示:
最后若是已经收到完整的IP数据包,则tfIpIncomingPacket()函数凭证IP数据包中的协议字段的协议号,挪用响应的协议包处置惩罚函数举行处置惩罚。在下列代码中,当协议号为UDP时,则挪用tfUdpIncomingPacket()函数,当数据包协议为IP-in-IP协议(协议号4)时,会递归挪用tfIpIncomingPacket()函数,代码实现如下所示:
六、误差原理剖析
1、CVE-2020-11896
前文已经先容tfIpIncomingPacket()函数的实现历程,第二步的数据裁剪是误差的缘故原由,如下代码所示:
pktuLinkDataLength保存目今分片的巨细,pktuChainDataLength保存整个IP数据包的巨细。若是执行上述操作,将导致一个纷歧致性的状态,其中pkt->pktuChainDataLength==pkt->pktuLinkDataLength,但可能有pkt->pktuLinkNextPtr指向其他分片。更进一步的其中链表上分片的总数据巨细可能大于存储在pktuChainDataLength变量中的巨细。这种操作导致的纷歧致性将会导致后续报文处置惩罚爆发异常。
通过简朴地设置过失的IP包分片是无法触发误差的,由于裁剪事后的分片数据在后续的tfIpReassemblePacket()函数操作中会凭证pktuChainDataLength的巨细,重新建设分片链表,不会造成纷歧致的状态。理想的流程是先完因素片链表的建设,再举行链表数据总巨细的裁剪流程,这样就会进入纷歧致的状态。
为了在IP层处置惩罚分片数据包并触发执行有问题的流程代码,可以使用IP-in-IP数据包。关于分片的IP-in-IP数据包,tfIpIncomingPacket()函数将至少递归挪用两次,一次用于IP隧道包的内层IP数据包,多次用于外层IP数据包(每处置惩罚一个外层IP包分片算作一次)。
tfIpIncomingPacket()函数在处置惩罚IP隧道数据包的时间将内部IP数据包作为非分片数据包举行处置惩罚。内部数据包现在由多个分片组成,但在IP报头中标记为非分片(MF=0),以是它不会再进入tfIpReassemblePacket()函数举行重组。它现在由一个链表中的几个单独的tsPacket链接组成,每个链接都有一个单独的pktuLinkDataLength值�K剂肯旅娴睦�,它将有助于明确误差的成因:
● Inner IP packet: IPv4{len=32, proto=17}/UDP{checksum=0, len=12},其中包括1000字节的数据’A’。
● Outer IP packet (fragment 1): IPv4{frag offset=0, MF=1, proto=4, id=0xabcd} ,其中包括40字节的IP数据。
● Outer IP packet (fragment 2): IPv4{frag offset=40, MF=0, proto=4, id=0xabcd} ,其中数据负荷为988字节。
为了绕过UDP校验,将校验和字段checksum设置为0。实例中的分片结构如下图所示:
当Treck协议栈处置惩罚外部分片时,它使用tsUserPacket结构中的pktuLinkNextPtr字段来链接它们。如前所述,当tfIpIncomingPacket()函数处置惩罚内部IP数据包(协议为4,IP-in-IP)时,它已经完成了分片数据的重组(内部IP数据包由链接在一起的两个tsPacket结构体现)。分片数据重组后的链表结构如下图所示:
由于tfIpIncomingPacket()函数在举行有用性判断时,只思量tsUserPacket中的pktuChainDataLength字段(而不是pktuLinkDataLength),以是在处置惩罚内部IP包时将进入过失的链表长度的裁剪流程,从而导致了问题。
内部IP包通过了IP头完整性检查,在该例子中,内部IP包的总长度(32)小于链表数据长度(1000+8+20=1028),因此Treck协议栈将实验过失地修剪数据包,要领是将字段pktuLinkDataLength和pktuChainDataLength设置为相同的值ipTotalLength(在我们的示例中为32)。这导致内部IP数据包由链接在一起的两个tsPacket结构体现,但它们的数据总长度大于pktuChainDataLength字段(修剪后pktuChainDataLength字段不是1028字节,而是即是32)。经由数据长度裁剪后的链表结构如下图所示:
现在已经使得链表抵达了纷歧致的状态,下面将先容怎样使用这种纷歧致的状态来导致内存破损。
在Treck协议栈代码中至少有一个代码路径可以将分片数据复制到单个一连缓冲区中。详细的执行路径为:
tfUdpIncomingPacket() -> tfSocketIncomingPacket() -> tfCopyPacket()。下面的代码是tfSocketIncomingPacket()函数处置惩罚UDP数据报的代码的一部分,如下代码所示:
这段代码中tfSocketIncomingPacket()函数挪用tfGetSharedBuffer()申请内存,其巨细基于pktuChainDataLength字段的值,然后通过tfCopyPacket()函数将数据包的差别分片逐个复制到新分派的内存空间中,爆发溢出的代码如下所示:
由于两个分片中的pktuLinkDataLength之和为1000字节,后续的tfCopyPacket函数将会把1000字节的数据拷贝到这段内存中,这将导致堆溢出。
2、CVE-2020-11898
正如前文形貌怎样触发CVE-2020-11896误差那样,Treck TCP/IP协议栈无法准确处置惩罚通过IP-in-IP隧道传入的IPv4分片。这也可能允许未经身份验证的攻击者从堆中走漏内存�?梢越幽梢韵率纠傩形蟛畲シⅲ�
● 内部IP数据包:IPv4 {ihl = 0xf,len = 100,proto = 0},有用载荷为'\ x00'* 40 +'\ x41'* 100。
● 外部IP数据包(分片1):IPv4 {frag offset = 0,MF = 1,proto = 4,id = 0xabcd},其中24个字节来自内部IP数据包有用负载。这意味着将复制20个字节的IP标头,外加4个空字节。
● 外部IP数据包(分片2):IPv4 {frag offset = 24,MF = 0,proto = 4,id = 0xabcd},来自内部IP数据包的其余字节作为有用负载。
实例中的分片结构如下图所示:
这里ihl为0xf,体现为最大IP选项,长度为60字节,数据包总长度total_length为100。当网络协议栈收到两个分片时,它将使用tfIpReassemblePacket()函数重新组装它们。分片数据重组后的链表结构如下图所示:
该tfIpReassemblePacket()函数使用tsUserPacket结构中的字段pktuLinkNextPtr链接两个分片。若是启用了IP-in-IP隧道传输,则内部IP数据包将随后由tfIpIncomingPacket()函数中处置惩罚,修剪后的pktuChainDataLength字段不是160,而是即是100。经由数据长度裁剪后的链表结构如下图所示:
内部IP数据包通过IP标头完整性检查,由于仅思量了tsUserPacket的pktuChainDataLength字段(而不思量pktuLinkDataLength)。由于在标准IP头部(20个字节)之后有4个空字节,并且一个空字节代表IP选项的末尾,IP选项剖析通过检查。由于内部IP数据包包括无效的IPv4协议编号(Protocol为0),进入default分支,然后直接进入TM_IP_LOCAL_FLAG分支。如下代码所示:
因此网络协议栈将通过发送类型为3(目的不可达)和代码为2(协议不可达)的ICMP过失新闻来拒绝该数据包。如下代码所示:
认真建设过失数据包的是tfIcmpErrPacket()函数。它分派一个新的数据包,初始化一些ICMP头部字段。如下代码所示:
最后从后续数据包(内部IP数据包)中复制一些数据。复制部分如下代码所示:
如代码所见,tfIcmpErrPacket()函数通过获取IP报头长度(以字节为单位加上8,在现真相形下为60 + 8 = 68)与pktuLinkDataLength字段(以及被裁剪为100)之间的最小值来盘算要复制的字节数 。由于发送数据包的第一个分片的现实链路数据长度为24(而不是100),因此tfIcmpErrPacket()函数将从堆中复制68-24 = 44字节的特殊数据。然后设置v12_icmpErrPacket中相关数据。如下代码所示:
最后挪用tfIpSendPacket()函数发送icmp_ErrPacket包到目的地址,这将导致44字节的信息泄露。
3、CVE-2020-11910
CVE-2020-11910是越界读误差,该误差保存tfIcmpIncomingPacket函数中,该函数主要是处置惩罚ICMP包。tfIcmpIncomingPacket函数在处置惩罚装备收到类型为3,code为4的ICMP包的时间,代码并没有验证后续数据的长度,直接就会见了对应位置的数据,造成了越界读误差。如下代码所示:
4、CVE-2020-11911
CVE-2020-11911是未授权的敏感信息更新误差,该误差保存tfIcmpIncomingPacket函数中,该函数主要是处置惩罚ICMP包。tfIcmpIncomingPacket函数在处置惩罚装备收到类型为18(Address mask reply)包的时间,代码并没有验证装备是否发送过类型17(Address mask request)请求,就直接更新了装备的子网掩码。如下代码所示:
七、CVE-2020-11898误差验证
远程攻击打印机,视频请到微信公众号中审查:验证视频。
八、参考
1、https://www.ietf.org/rfc/rfc2003.txt
2、https://www.ietf.org/rfc/rfc792.txt
3、https://www.ietf.org/rfc/rfc1853.txt
4、https://www.jsof-tech.com/ripple20/
5、https://kb.cert.org/vuls/id/257161
6、/article/1/11834.html
7、JSOF_Ripple20_Technical_Whitepaper_June20.pdf
尊龙凯官网入口起劲防御实验室(ADLab)
ADLab建设于1999年,是中国清静行业最早建设的攻防手艺研究实验室之一,微软MAPP妄想焦点成员,“黑雀攻击”看法首推者。阻止现在,ADLab已通过CVE累计宣布清静误差1000余个,通过 CNVD/CNNVD累计宣布清静误差800余个,一连坚持国际网络清静领域一流水准。实验室研究偏向涵盖操作系统与应用系统清静研究、移动智能终端清静研究、物联网智能装备清静研究、Web清静研究、工控系统清静研究、云清静研究。研究效果应用于产品焦点手艺研究、国家重点科技项目攻关、专业清静服务等。


京公网安备11010802024551号