更多安全资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn)
一、前言
近期,国外安全研究人员在多个被广泛使用的开源TCP/IP协议栈发现了多个漏洞,这一系列漏洞统称为AMNESIA33。这些漏洞广泛存在于嵌入式和物联网设备中,影响了多个行业领域(包括医疗、运输、能源、电信、工业控制、零售和商业等),目前已知范围内涉及了超150家供应商以及数以百万计的设备。与URGEN11和Ripple20不同的是,AMNESIA33影响的是多个开源TCP/IP协议栈,因此这些漏洞可以悄无声息地影响到无数个代码库、开发团队与各个公司的产品。目前已知的漏洞涉及到了智能家居、工厂PLC、SCADA设备与工控交换机,电力监控等设备。
这些漏洞存在于uIP、FNET、picoTCP和Nut/Net等开源协议栈上,影响TCP/IP协议栈的多个组件,包括DNS、IPv6、IPv4、TCP、ICMP、LLMNR和mDNS等。其中包括多个严重漏洞,它们的CVE编号分别为CVE-2020-17437、CVE-2020-17443、CVE-2020-24338、CVE-2020-24336、CVE-2020-25111。
CVE-2020-17437(CVSS评分8.2)、CVE-2020-17443(CVSS评分8.2)可导致设备拒绝服务。CVE-2020-24338、CVE-2020-24336、CVE-2020-25111(这三个CVSS评分均为9.8)都可导致远程代码执行(RCE)。其它28个漏洞的严重程度各异,CVSS评分分别从4到8.2。
由于IoT、OT、IT设备供应链的特性,漏洞影响的设备众多,影响范围广且持续时间长,漏洞修复的实施较困难。同时,由于uIP、picoTCP开源协议栈已经不再维护,所以部分漏洞没有补丁,很多产品只能寻找替代技术方案或者是增加防范措施。
因此,启明星辰 ADLab 对相关漏洞进行了分析 ,并成功复现了多个漏洞,开发了 AMNESIA33 相关漏洞检测技术,并提取了流量监控特征,这些技术正在应用到我们的安全产品中。 为了缓解漏洞的影响,我们 提出 下列 防范建议 。 二、防范建议
对于这些漏洞的防范缓解措施,我们建议采取如下几个措施:
配置内网设备的DNS服务器为内网DNS服务器。
- 如不必要,请关闭IPv6设置。
利用漏扫产品识别出采用问题协议栈的设备资产,对组织内可能存在问题的IoT、OT和IT设备进行风险评估。
防火墙及IPS产品加入AMNESIA33漏洞攻击识别特征,监控恶意流量。
- 如不必要,设备不要暴露在公网。
尽可能更新相关受影响协议栈到最新版本。
下表是部分已经修复的协议栈及版本:
TCP/IP协议栈 | 修复版本 |
FNET | 4.70及以上 |
uIP-Contiki-NG | 4.6.0及以上 |
Nut/Net | 5.1及以上 |
CISA联盟分享了13个涉及到AMNESIA33漏洞的公司的产品修复建议,包括了Microchip、Siemens等公司的产品,详见参考链接[5]。
三、相关概念介绍
1、DNS协议解析
DNS的请求和响应的基本单位是DNS报文(Message)。请求和响应的DNS报文结构是完全相同的,每个报文都由以下五段(Section)构成: DNS Header是每个DNS报文都必须拥有的一部分,它的长度固定为12个字节。Question部分存放的是向服务器查询的域名数据,一般情况下它只有一条Entry。每个Entry的格式是相同的,如下所示: QNAME是由labels序列构成的域名。QNAME的格式使用DNS标准名称表示法。这个字段是变长的,因此有可能出现奇数个字节,但不进行补齐。DNS使用一种标准格式对域名进行编码。它由一系列的label(和域名中用.分割的label不同)构成。每个label首字节的高两位用于表示label的类型。RFC1035中分配了四个里面的两个,分别是:00表示的普通label,11(0xC0)表示的压缩label。 Answer、Authority和Additional三个段的格式是完全相同的,都是由零至多条Resource Record(资源记录)构成。这些资源记录因为不同的用途而被分开存放。Answer对应查询请求中的Question,Question中的请求查询结果会在Answer中给出,如果一个响应报文的Answer为空,说明这次查询没有直接获得结果。 RR(Resource Record)资源记录是DNS系统中非常重要的一部分,它拥有一个变长的结构,具体格式如下:NAME:它指定该条记录对应的是哪个域名,格式使用DNS标准名称表示法
TYPE:资源记录的类型。
CLASS:对应Question的QCLASS,指定请求的类型,常用值为IN,值为0x001。
TTL(Time To Live)资源的有效期:表示你可以将该条RR缓存TLL秒,TTL为0表示该RR不能被缓存。TTL是一个4字节有符号数,但是只使用它大于等于0的部分。
RDLENGTH:一个两字节非负整数,用于指定RDATA部分的长度(字节数)。
RDATA:表示一个长度和结构都可变的字段,它的具体结构取决于TYPE字段指定的资源类型。
域标签label在DNS数据包里被编码,每个普通标签的第一个字节代表这个标签的长度,剩下的字母数字字符为标签本身(一些特殊字符也是可以的),但是最终结尾的字符一定是以空字节结尾(即0x00),用来表示域名的结束。举个例子,如下图所示,域标签第一个字符是0x03,这代表第一个标签长度为3(即0x77 0x77 0x77 == “www”),同理,0x62 0x61 0x690x64 0x75 == “baidu”,最后可以看到以0x00结尾。
2、TCP紧急模式
为了发送重要协议数据,TCP提供了一种称为紧急模式(urgentmode)的机制,TCP协议在数据段中设置URG位,表示进入紧急模式。通过设置紧急模式,发送方可以在发送队列中优先发送这部分的数据,而且不用在发送队列中排队,而接收方可以对紧急模式采取特殊的处理。这种方式数据不容易接受被阻塞,服务器端程序会优先接受这些紧急的数据,而不用进行排队处理。在TCP报文中定义了两个字段来标示紧急模式,一个URG标志,该标志表示报文中有紧急数据,另一个标志是紧急指针,它标示紧急数据在传输数据中偏移位置。如下图所示:
四、漏洞分析
下面我们对几个CVSS评分较高的漏洞进行分析: 1、CVE-2020-17437 CVE-2020-17437存在于uIP协议栈的uip.c文件的uip_process函数中,该函数主要是处理ip/tcp报文,下图是uIP协议栈对TCP报文中带有TCP_URG紧急指针标识时的处理代码,如果编译时配置了UIP_URGDATA,则程序会走到下面的if分支,对紧急指针数据进行专门处理。但是在默认情况下,UIP_URGDATA并没有配置。代码会进入到else分支,程序会跳过处理紧急指针数据,并修改uip_len的数值。程序在修改uip_len的时候并没有判断紧急指针的值,当uip_len的值特别小,而紧急指针的值urgp特别大时,就会引起整数溢出,导致设备重启或者是越界读写。
2、CVE-2020-24338该漏洞出现在picoTCP/IP协议栈中解析域名label的pico_dns_decompress_name()函数中,该函数具体实现如下代码所示:
第95、96行初始化iterator,name指向待解压缩的labels,dest_iterator指向存放解压出来的labels的缓冲区,大小为256字节。第97行开始为while循环,读取到字符串结尾空字节退出。第98行,通过iterator&0xC0判断label类型,如果为压缩label,则通过packet定位到普通label所在的位置,如果为普通label直接进入else代码块中,第107行,调用memcpy将普通label拷贝到dest_iterator中。我们知道dest_iterator缓冲区大小只有256字节,而while循环退出条件为读到字符串结尾空字节,因此当name长度超过256字节时,导致dest_iterator缓冲区溢出。
3、CVE-2020-24336该漏洞出现在contiki协议栈中的ip64_dns64_4to6()中,该函数功能是将ipv4类型的DNS数据包转换成ipv6类型的DNS数据包,关键代码如下:
遍历Answer区段并更新到ipv6类型的Answer区段中。从第209行开始转换资源记录,具体实现代码如下所示:
首先判断TYPE是否是DNS_TYPE_A,DNS_TYPE_A表示该资源记录为ipv4主机地址,然后将对应区段拷贝到acopy中。第220行,从资源记录中直接取RDLENGTH,前文已介绍,该区段表征RDATA的长度。第227行,判断len长度是否等于4,这里正常情况,len应该为4,因为ipv4地址长度为4个字节。如果len不等于4,则进入else语句中,直接调用memcpy进行RDATA数据拷贝。这里是存在问题的,Ipv4主机地址长度不等于4,并没有验证主机地址的合理性而且len最大为0xFFFF,直接拷贝可能导致缓冲区溢出。
4、 CVE-2020-25111在使用Nut/Net协议栈的设备中,NutDnsGetResourceAll()是处理DNS请求的函数,其中处理DNS答复的函数是DecodeDnsQuestion(),处理域标签的函数是ScanName(),漏洞就出现在ScanName()函数中。如下图所示,cp为指向域名第一个字节的指针(即第一个域标签的长度字节),*npp为即将被解析的域名buffer,通过strlen()将整个域名长度赋值给rc,然后基于rc分配*npp buffer,之后通过一个while,循环处理每一个label。问题显而易见,cp是攻击者可控的,由此可以控制*npp的大小。而对于标签的长度,即len变量,直接从数据包中得到,并没有做任何边界检查,然后通过while循环处理。因此可以对len设置任意的值,即攻击者对*npp buffer可控的长度。由此可以在堆中造成越界写,这可导致远程代码执行(RCE)。
5、CVE-2020-17443CVE-2020-17443存在于PicoTCP协议栈pico_icmp6.c文件中。问题代码位于pico_icmp6_send_echoreply()函数中,该函数的主要功能是回复ICMPv6应答数据包以响应对端的ICMPv6Echo(ping)请求。
我们可以看到,第68行,replay结构的缓冲大小基于echo的报文中transport_len变量。 在第84行,程序从echo->payload向reply->payload地址复制了长度为echo->transport_len- 8大小的数据。 注意,如果echo->transport_len小于 8,echo->transport_len - 8会导致整数溢出,memcpy操作会导致缓冲区溢出。在PicoTCP协议栈攻击者通过构造恶意的ICMPv6数据包,这个恶意的数据包ICMP报头小于8,会导致设备重启或拒绝服务。
五、漏洞验证
CVE-2020-17437漏洞验证视频
CVE-2020-17443漏洞验证视频
[3] https://www.zdnet.com/article/amnesia33-vulnerabilities-impact-millions-of-smart-and-industrial-devices/
[4] https://tools.ietf.org/html/rfc1035
[5] https://us-cert.cisa.gov/ics/advisories/icsa-20-343-01
启明星辰积极防御实验室(ADLab)
ADLab成立于1999年,是中国安全行业最早成立的攻防技术研究实验室之一,微软MAPP计划核心成员,“黑雀攻击”概念首推者。截止目前,ADLab已通过CVE累计发布安全漏洞近1100个,通过 CNVD/CNNVD累计发布安全漏洞900余个,持续保持国际网络安全领域一流水准。实验室研究方向涵盖操作系统与应用系统安全研究、移动智能终端安全研究、物联网智能设备安全研究、Web安全研究、工控系统安全研究、云安全研究。研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。