0x00 漏洞背景
2020年6月16日,360工业及车联网安全事业部 监测发现 Treck Inc. 官方发布了针对 Treck TCP/IP协议栈 中共19个漏洞的安全通告。其中有4个漏洞CVSS评分高于9分。360工业及车联网安全事业部 在第一时间,针对该漏洞进行了深入分析。
Treck Inc. 所开发的网络协议栈包括底层的TCP/IP协议,以及各种应用层网络协议。Treck的网络协议栈被广泛的用于各类实时嵌入式系统以及工控设备中。
本次公布的漏洞中,有两个漏洞存在远程代码执行的可能。其中 CVE-2020-11896 是存在于IP层解析模块中的漏洞,攻击者可以通过发送精心构造的UDP报文触发Treck协议栈中IP层的分片重组功能,造成远程代码执行。而 CVE-2020-11901 是存在于DNS解析模块中的漏洞,该漏洞可通过回复设备发出的单条DNS请求报文触发,从而造成远程代码执行。
全部公开的19个漏洞已经在 6.0.1.67 及更高的版本中得到了修复,厂商也提出了针对不同场景下的漏洞缓解措施。360工业及车联网安全事业部 建议相关用户,根据实际情况采取适合的方法对漏洞进行修复。
0x01 风险等级
360工业及车联网安全事业部针对Ripple20中19个漏洞进行了风险评估,详情见下表:
CVE ID | 漏洞描述 | 威胁等级 | 影响面 |
---|---|---|---|
CVE-2020-11896 | IPv4 / UDP组件中对长度参数不一致的处理不当,可能导致远程代码执行。 | 严重 | 广泛 |
CVE-2020-11897 | IPv6组件中对于长度参数不一致的处理不当,可能导致越界写入。 | 严重 | 广泛 |
CVE-2020-11898 | IPv4 / ICMPv4组件中对长度参数不一致的处理不当,可能导致敏感信息泄露。 | 严重 | 一般 |
CVE-2020-11899 | IPv6组件中的输入验证不正确,可能导致越界读取/拒绝服务。 | 中危 | 一般 |
CVE-2020-11900 | IPv4隧道组件中可能存在双重释放,可能导致释放后使用。 | 高危 | 一般 |
CVE-2020-11901 | DNS解析器组件中存在输入验证不正确。可能导致远程代码执行。 | 严重 | 广泛 |
CVE-2020-11902 | IPv6OverIPv4隧道组件中的输入验证不正确,可能造成越界读取。 | 高危 | 一般 |
CVE-2020-11903 | DHCP组件中存在越界读取。可能导致敏感信息泄露。 | 中危 | 一般 |
CVE-2020-11904 | 内存分配组件中存在整数溢出,可能造成越界写入。 | 高危 | 一般 |
CVE-2020-11905 | DHCPv6组件中存在越界读取问题,可能造成越界读取。 | 中危 | 一般 |
CVE-2020-11906 | 以太网链路层组件中存在输入验证不正确,可能造成整数溢出。 | 中危 | 一般 |
CVE-2020-11907 | TCP组件中对参数长度不一致的处理不当,可能造成整数溢出。 | 中危 | 一般 |
CVE-2020-11908 | DHCP组件中的Null Termination不正确,可能导致敏感信息泄露。 | 中危 | 一般 |
CVE-2020-11909 | IPv4组件中的输入验证不正确,可能导致整数溢出。 | 中危 | 一般 |
CVE-2020-11910 | ICMPv4组件中的输入验证不正确,可能导致越界读取。 | 中危 | 一般 |
CVE-2020-11911 | ICMPv4组件中的访问控制不正确 | 中危 | 一般 |
CVE-2020-11912 | TCP组件中的输入验证不正确,可能导致越界读取。 | 中危 | 一般 |
CVE-2020-11913 | IPv6组件中的输入验证不正确,可能导致越界读取。 | 中危 | 一般 |
CVE-2020-11914 | ARP组件中的输入验证不正确,可能导致越界读取。 | 中危 | 一般 |
0x02 漏洞分析
前置知识
在针对CVSS评分10分的CVE-2020-11896的漏洞进行分析之前,首先需要简单的了解一下两个IP协议中的概念--IP分片与IP隧道。
IP分片
由于不同的网络环境对于IP报文的长度限制不同。所以当转发长度大于该网络允许的最大长度的报文时,就需要对该报文进行IP分片,将原始的IP报文分成多个符合长度要求的短IP报文。而这些报文在到达目的地后会通过IP协议进行重组,恢复成原始的IP报文。
IP隧道
IP隧道允许在两个单独的网络之间进行虚拟的点对点链接。 通过将一个数据包(可能是IP数据包)封装在另一个数据包中,可以使内部数据包具有与外部数据包不同的源地址和目标地址。(VPN就是一种IP隧道)。而触发此漏洞需要使用一种最简单的IP隧道 IP-in-IP。IP-in-IP协议在IP协议层外侧再封装一层IP协议,以达到进行虚拟点对点链接的目的。
代码分析
Treck的协议栈使用结构体tsPacket来存储所有与数据包的基本信息
struct tsPacket {
ttUserPacket pktUserStruct;
ttSharedDataPtr pktSharedDataPtr; // Point to corresponding sharable ttSharedData
struct tsPacket * pktChainNextPtr; // Next packet (head of a new datagram in a queue)
struct tsDeviceEntry * pktDeviceEntryPtr; // pointer to network Device struct
union anon_union_for_pktPtrUnion pktPtrUnion;
tt32Bit pktTcpXmitTime;
tt16Bit pktUserFlags;
tt16Bit pktFlags;
tt16Bit pktFlags2;
tt16Bit pktMhomeIndex;
tt8Bit pktTunnelCount; // Number of times this packet has been decapsulated. Initially set to zero.
tt8Bit pktIpHdrLen; // Number of bytes occupied by the IP header.
tt8Bit pktNetworkLayer; // Specifies the network layer type of this packet (IPv4, IPv6, ARP, etc).
tt8Bit pktFiller[1];
};
ttUserPacket结构体中保存了数据包数据相关的数据。
struct tsUserPacket {
void * pktuLinkNextPtr; // Next tsUserPacket for fragmented data
ttUser8BitPtr pktuLinkDataPtr; // Pointer to data
ttPktLen pktuLinkDataLength; // Size of data pointed by pktuLinkDataPtr
ttPktLen pktuChainDataLength; // Total packet length (of chained fragmented data). Valid in first link only.
int pktuLinkExtraCount; // Number of links linked to this one (not including this one). Valid in first link only.
};
- pktuLinkNextPtr:Treck协议栈在处理分片的情况时,使用链表的结构存储分片的信息。一个tsUserPacket就对应一个分片,而 pktuLinkNextPtr指针就是指向的是下一个分片,当后面没有分片更多分片时(包括不使用分片,即只有一个分片时),pktuLinkNextPtr指针设为Null。
- pktuLinkDataPtr:指向数据存储的地址。
- pktuLinkDataLength:本分片中所接收到数据的长度。
- pktuChainDataLength:整个链表中所有接收到的数据长度(只有链表中第一个节点的值是有效的)。
当数据在不同层级的协议中传递时,如将以太网帧传递到IP层时,Treck协议栈会修改tsUserPacket结构体中的数据,该结构体就从以太网帧变为了IP报文。
pkt->pktuLinkDataPtr = pkt->pktuLinkDataPtr + 0xe;
pkt->pktuLinkDataLength = pkt->pktuLinkDataLength - 0xe;
pkt->pktuChainDataLength = pkt->pktuChainDataLength - 0xe;
传入的数据报文由具有相同命名约定tf*IncomingPacket的函数处理(据我们所知),其中*是协议名称。 对于以太网/ IPv4,数据包将由函数tfEtherRecv,tfIpIncomingPacket处理。
Treck堆栈在函数tfIpReassemblePacket中处理IP分片的重组,该方法是从tfIpIncomingPacket调用的。每当接收到发往设备的IP分片时,就会调用此函数。如果缺少分片,函数将返回NULL。当所有分片都已经收到并且没有连续没有缺失(通过More Fragements和Fragment Offset确定),则协议栈将使用pktuLinkNextPtr字段将所有的分片链接在一起,并将数据包传递给下一层进行进一步处理。 进行IP分片重组的过程中,并不意味着将数据包复制到连续的存储块,而是简单地将它们在链表中链接在一起。
Root Cause分析
在函数tfIpIncomingPacket中,Treck协议栈在处理头部报文与实际接收到的长度不同时,使用了一种比较简单的处理方式。
if ((uint)ipTotalLength <= pkt->pktuChainDataLength) {
if ((uint)ipTotalLength != pkt->pktuChainDataLength) {
pkt->pktuChainDataLength = (uint)ipTotalLength;
pkt->pktuLinkDataLength = (uint)ipTotalLength;
}
...
}
- ipTotalLength是IP头部中两字节的TotalLength字段
- pktuChainDataLength是实际收到的IP层数据长度
当tfIpIncomingPacket接收到的IP报文中,TotalLength小于实际接收到的数据时。Treck协议栈选择接受IP头部中TotalLength所声明的长度,直接丢弃掉接收到的多余数据。将pktuChainDataLength和pktuLinkDataLength同时赋值为TotalLength。这样简单的处理方式在解析常规IP报文时看起来并不会产生什么异常,不论是否使用了分片的功能。但是当使用IP-in-IP协议时,这样简单的处理则会造成内存破坏。
但是当Treck协议栈在处理精心构造的IP-in-IP数据包时,则会造成堆溢出。数据包的构造如下图所示:
IP层:包含了两个分片。第一个分片包含了40byte的数据,其中包括上层协议(IP-in-IP、UDP)的包头,以及12字节的上层协议的数据;第二个分片中的包含了988字节,全部的都是上层协议的数据。
IP-in-IP层:未开启IP分片(MF=0),头部中TotalLength为32(此字段造成pktuChainDataLength与TotalLength的不同以触发漏洞)
UDP层:length字段设为为12(为了进入可以造成堆溢出的逻辑分支)
Treck协议栈在处理上述构造的报文时,则会产生堆溢出,具体流程如下:
-
tfIpIncomingPacket接收外层IP分片,并交给tfIpReassemblePacket函数处理分片重组
-
tfIpReassemblePacket函数在接收到全部外层IP分片后,交给协议栈解析上层协议
-
协议栈解析出上层为IP-in-IP协议后,对pk进行如代码所示的操作,然后再次将结构体交给tfIpIncomingPacket函数处理IP-in-IP(即IP)协议。
pkt->pktuLinkDataPtr = pkt->pktuLinkDataPtr + 20;
pkt->pktuLinkDataLength = pkt->pktuLinkDataLength - 20;
pkt->pktuChainDataLength = pkt->pktuChainDataLength - 20;
-
tfIpIncomingPacket函数在处理报文时,由于TotalLength < pkt->pktuChainDataLength(32 < 1028)。所以将pkt->pktuLinkDataLength和pkt->pktuChainDataLength赋值为32。并交给协议栈继续处理内层报文。
-
协议栈解析出内层为UDP协议后,继续根据UDP包头的长度修改pkt的指针以及长度字段,交给tfUdpIncomingPacket处理UDP协议。
-
tfUdpIncomingPacket在处理UDP数据时,会根据pkt->pktuChainDataLength的大小4(32-IP头部长度20-UDP头部长度8)使用tfGetSharedBuffer函数申请一块内存,并使用tfCopyPacket函数将全部的数据拷贝到所分配的内存中。而拷贝的方式就是通过pktuLinkDataPtr指针递归的将数据拷贝到所分配的缓冲区中。由于要拷贝的数据长度为1000字节,远大于缓冲区分配的大小。所以在数据拷贝的过程中造成了堆溢出。
if (uVar2 <= sizeOfPacketBuffer) {
dst = tfGetSharedBuffer(0x54,pkt->pktuChainDataLength,0);
if (dst != NULL) {
tfCopyPacket(pkt,dst);
needToDrop = true;
local_10 = dst;
}
}
i = 0;
do {
memcpy(dst->pktuLinkDataPtr + i,src->pktuLinkDataPtr,src->pktuLinkDataLength);
i = i + src->pktuLinkDataLength;
src = (tsPacket *)src->pktuLinkNextPtr;
} while (src != NULL);
0x03 影响范围
Ripple20涉及到的厂商以及产品较多,部分已经得到了厂商的确认,而还有一部分还处于待定状态。全部涉及到的厂商在下图展示:
大部分确认的厂商已经在自己的官网中公布了涉及到Ripple20的产品,以及对应的解决措施。360工业及车联网安全事业部 收集了各厂商针对此次Ripple20漏洞的公告:
Aruba Networks
B|Braun USA
- https://www.bbraunusa.com/en/products-and-therapies/customer-communications.html
- https://www.bbraunusa.com/content/dam/b-braun/us/website/customer_communications/Skyline Response_Outlook_6.9.2020_FINAL1.pdf
Baxter U.S.
Boston Scientific / Guidant Medical
- https://www.bostonscientific.com/content/dam/bostonscientific/corporate/product-security/BSC-Statement-on-Ripple20-Treck-Vulnerability-Rev1-25Jun2020.pdf
- https://www.bostonscientific.com/en-US/customer-service/product-security/product-security-information.html
CARESTREAM
- https://www.carestream.com/en/us/services-and-support/cybersecurity-and-privacy
- https://www.carestream.com/en/us/-/media/publicsite/resources/service-and-support-publications/product-security-advisory---ripple20.pdf?sc_lang=en
CATERPILLAR
Cisco
Dell / EMC
- https://www.dell.com/support/article/fr-fr/sln321835/dsa-2020-150-dell-client-platform-security-update-for-treck-tcp-ip-stack-vulnerabilities-in-teradici-firmware-and-remote-workstation-cards?lang=en
- https://www.dell.com/support/article/fr-fr/sln321727/dsa-2020-143-dell-client-platform-security-update-for-intel-platform-updates-2020-1?lang=en
- https://www.dell.com/support/article/fr-fr/sln321836/dell-response-to-the-ripple20-vulnerabilities?lang=en
EATON
DIGI
Elmic / KASAGO
- https://www.elwsc.co.jp/news/4136/
- https://www.elwsc.co.jp/wp-content/uploads/2020/06/KASAGO202006-1.pdf
Green Hills Software
HP
HPE
INTEL
KASAGO
McAfee
- https://kc.mcafee.com/corporate/index?page=content&id=SB10321
- https://kc.mcafee.com/corporate/index?page=content&id=KB93020
NetApp
ROCKWELL AUTOMATION
Schneider
Teradici
Treck
Xerox
0x04 修复方式及缓解措施
设备供应商的缓解措施
- 确定是否使用易受攻击的Treck堆栈
- 联系Treck了解风险
- 更新到最新的Treck堆栈版本(6.0.1.67或更高版本)
- 如果无法更新,请考虑禁用易受攻击的功能
相关设备用户
- 联系设备供应商进行更新或漏洞缓解
网络管理者的缓解措施
- 最好的缓解措施是将所有设备的修补程序版本更新。
- 如果无法更新设备,建议执行以下步骤:
- 将嵌入式和关键设备在网络中的暴露程度保持在最低水平;并关闭所有非必要的网络连接功能
- 将操作技术网络和设备隔离在防火墙后,并将其与业务网络隔离
- 仅启用安全的远程访问方法
- 阻止异常IP流量
- 通过深度数据包检查来阻止网络攻击,以减少对Treck嵌入式启用TCP / IP的设备的风险
- 流量过滤是一种有效的技术,可以适当地应用于您的网络环境。过滤选项包括:
- 规范化或阻止IP分片
- 如果不需要,请禁用或阻止IP隧道(IPv6-in-IPv4或IP-in-IP隧道)
- 禁止IP源路由以及以及所有不推荐使用的IPv6功能,例如路由头
- 强制执行TCP检查,拒绝格式错误的TCP数据包
- 阻止未使用的ICMP控制消息,例如MTU更新和地址掩码更新
- 通过安全的递归服务器或DNS检查防火墙规范DNS
- 提供DHCP / DHCPv6安全性,并具有DHCP监听等功能
- 如果未在交换基础架构中使用,请禁用/阻止IPv6多播功能
- 在可以使用静态IP的网络禁用DHCP
- 使用网络IDS和IPS签名
- 使用网络分段(如果可用)
0x05 参考链接
https://www.jsof-tech.com/ripple20
https://treck.com/vulnerability-response-information
https://nvd.nist.gov/vuln/detail/CVE-2020-11896
https://gist.github.com/SwitHak/5f20872748843a8ad697a75c658278fe