一、漏洞信息1.漏洞简介漏洞名称:WindowsTCP/IP远程执行代码漏洞漏洞编号:CVE??-2020-16898漏洞类型:设计弱点漏洞影响:代码执行CVSS评分:9.8开发难度:中基本权限:不需要2.组件概述TCP/IP是互联网上使用的一种通信协议。在早期版本的Windows中,TCP/IP是一个单独的可选组件,可以像任何其他协议一样删除或添加。从WindowsXP/Server2003开始,TCP/IP已经成为操作系统的核心组成部分,无法删除。将TCP/IP作为Windows的核心组件是有意义的,因为它的功能对于MicrosoftWindowsServer上的网络操作和ActiveDirectory域环境尤为重要。整个ActiveDirectory体系结构基于DNS层次结构并依赖于TCP/IP传输协议。MicrosoftWindows中的TCP/IP功能在内核级别运行,由驱动程序tcpip.sys提供。驱动程序处理所有传入和传出的TCP/IP通信,包括解析从网络接口接收的数据包,以及解释此数据并将其传递给更高级别的组件。3.漏洞利用该漏洞主要是由于WindowsTCP/IP协议栈在处理选项类型为25(0x19,递归DNS服务器选项)且长度字段为偶数的ICMPv6路由广播包时的处理逻辑存在缺陷,导致远程代码执行漏洞。成功利用此漏洞的攻击者可以在目标机器(主机或服务器)上执行任意代码。4.该漏洞影响MicrosoftWindows101709MicrosoftWindows101803MicrosoftWindows101809MicrosoftWindows101903MicrosoftWindows101909MicrosoftWindows102004MicrosoftWindowsServer2019MicrosoftWindowsServer,version1903MicrosoftWindowsServer,version1909MicrosoftWindowsServer,version20045。官方解决方案:微软官方已经针对该漏洞发布了安全更新补丁,补丁地址:https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898临时解决方案解决方案:管理员启动powershell或cmd,输入以下命令查看所有网络IPv6接口列表及对应的索引号:netshintipv6shint示例输出如下:确认网络接口的RDNSS功能已开启:netshintipv6shintIdxnumber执行以下命令关闭RDNSS功能(Idxnumber替换为要关闭的网络接口的Idx值):netshintipv6setintIdxnumberrabaseddnsconfig=disable示例输出如下:此时再次确认接口的RDNSS启用,RDNSS功能已关闭:2.漏洞复现1.环境搭建l目标机器:Windows101809x64lTarget机器操作:不需要任何操作,可以和攻击机器正常通信二、复现过程1、通过各种方式获取目标主机的IPv6地址和MAC地址(具体方法可以自己摸索,相对simple)2.攻击机python3运行poc:3.目标机崩溃:3.漏洞分析1.基本信息漏洞文件:tcpip.sys漏洞函数:Ipv6pUpdateRDNSS()函数漏洞对象:ICMPv6路由广播optionstructure2.背景知识受限于问题的篇幅。这里就不详细介绍DNS配置的IPv6路由通告了。有关更多详细信息,请参阅RFC81061。基础知识IPv6RouterAdvertisment(RA)选项,也称为DNSRA选项,允许IPv6路由器向IPv6主机广播DNSRecursiveServerAddress(DNS递归路由器地址)列表和DNSSearchList(DNS搜索列表),主要用于IPv6主机上的DNS名称解析和域后缀处理。IPv6邻居发现(ND,IPv6NeighborDiscovery)和IPv6无状态地址自动配置(SLAAC,IPv6StatelessAddressAutoconfiguration)提供了使用一个或多个IPv6地址、默认路由器和一些其他参数来配置固定节点或移动节点的方法。每次漫游主机连接到另一个网络时,手动配置是不可能的。虽然静态配置是可能的,但通常不建议在笔记本电脑等通用主机上使用。例如,如果主机运行其自己的直接连接到全球DNS的递归名称服务器,则本地定义的名称空间将对主机不可用。访问DNS是几乎所有主机的基本要求,因此在没有任何DNS配置支持的情况下,IPv6SLAAC不能单独作为任何真实网络环境中的替代部署模型。对于IPv4环境下的DNS服务器来说,这些问题很容易解决。但是对于IPv6的网络环境,这些问题就显得比较棘手了。因此,RFC8106定义了一种基于DNSRA选项的机制,允许IPv6主机执行自动DNS配置。在通过IPv6SLAAC自动配置IPv6主机地址且没有DHCPv6基础设施或某些主机没有DHCPv6客户端的网络环境中,可以使用基于RA的DNS配置作为替代方案。但是,对于需要分发额外信息的网络,仍可能使用DHCPv6。在这些网络中,可能不需要基于RA的DNS配置。基于RA的DNS配置允许IPv6主机获取主机所连接链路的DNS配置(即DNS递归服务器地址和DNSSL)。此外,主机从提供链路配置信息的同一RA消息中了解此DNS配置。2、术语解释RecursiveDNSServer(RDNSS):递归DNS服务器,提供递归DNS解析服务的服务器,用于将域名转换成IP地址或解析成RFC1034和RFC1035中定义的PTR记录。RDNSS选项:用于将RDNSS信息传输到IPv6主机的IPv6RA选项[RFC4861]。DNSSearchList(DNSSSL):Pv6主机在进行DNS查询搜索时使用的DNS后缀域名列表,用于搜索短的不合格域名。DNSSL选项:用于将DNSSL信息传递给IPv6主机的IPv6RA选项。三、详细分析1、基本分析RFC8106规范了RDNSS选项,包含了RDNSS的地址。该信息使用现有的ND消息(如RA)作为载体。一台IPv6主机可以通过RA消息配置一个或多个RDNSSIPv6地址。(1)NeighborDiscoveryExtensionRFC8106定义的邻居发现中使用的IPv6DNS配置算法需要两种ND选项:RDNSS选项和DNSSL选项。与此漏洞相关的一个是RDNSS选项,另一个与CVE-2020-16899相关。(2)RDNSSOption结构RDNSSOption的整体结构如下:对于Length字段,如果Option只包含一个IPv6地址,则最小值为3。每增加一个RDNSS地址,长度增加2。接收主机使用此字段来确定选项中IPv6地址的数量。(3)IPv6Hosts中的流程当主机收到RA报文中的DNSoptions时,其处理流程如下:首先检查Lengh字段的合法性:是否大于等于最小值3,是否它满足(Length-1)%2==0;对于RDNSS选项,还要检查Address字段是否为单播地址;如果通过上述验证,主机应将选项的值依次复制到DNS存储库和解析器存储库。否则,主机必须丢弃这些选项。(4)崩溃分析首先分析dmp文件,查看崩溃部位:没有发现明显且有价值的CallStack信息,但发现最终导致崩溃的原因是GS机制的SecurityCookie验证失败,即也就是说,这个值被Overwritten了。那么它很有可能会溢出。另外只找到了tcpip!Ipv6pHandleRouterAdvertisement+0x1269这个函数,然后会直接报gsfailure。2、静态分析使用的文件是Windows101809x64,版本10.0.17763.316的tcpip.sys文件。(1)函数调用链根据崩溃站点信息,得到关键函数tcpip!Ipv6pHandleRouterAdvertisement(),首先确认该函数到漏洞函数的调用链。先查看其交叉引用关系:其上层调用函数为Icmpv6ReceiveDatagrams(),跟进,查看交叉引用关系:未发现显式函数调用。转至tcpip!Ipv6pHandleRouterAdvertisement()下层搜索:找到漏洞函数调用。至此,函数调用链可简单概括为:Icmpv6ReceiveDatagrams()->tcpip!Ipv6pHandleRouterAdvertisement()->Ipv6pUpdateRDNSS()(2)经过简单的漏洞函数分析,可以清楚顶层函数调用链的icmpv6ReceiveDatagrams()没有发现大量与漏洞相关的处理代码,在tcpip!Ipv6pHandleRouterAdvertisement()函数中发现了对漏洞函数Ipv6pUpdateRDNSS()的调用。根据crash分析,最后报了gsfailure,关键函数是tcpip!Ipv6pHandleRouterAdvertisement(),在函数开头确实发现了GS校验:那么很有可能是漏洞发生了溢出functionIpv6pUpdateRDNSS(),causingTheGSverificationofthefunctiontcpip!Ipv6pHandleRouterAdvertisement()called失败。进入漏洞函数Ipv6pUpdateRDNSS():首先获取RDNSS选项结构体,然后读取Length域,计算Address域有多少个Address值。确认有多少个Address后,进入循环,对每个Address进行处理。最重要的是分配合适的内存。这里还有一个判断,如果不是单播地址,直接忽略即可。处理的时候,有一个问题:假设Length的长度为4,那么计算完成后,AddressCount的值应该为1。此时,按照正常的逻辑,Ipv6pUpdateRDNSS()函数应该添加一个32字节(4*8)缓冲区,但分配缓冲区时只分配了24字节:sizeof(ND_OPTION_RDNSS)+sizeof(IN6_ADDR)=8+16=24,导致缓冲区溢出。根据RFC8106标准,Length字段的值应满足最小奇数为3的条件。WindowsTCP/IP堆栈在提供偶数Length值时错误地将缓冲区推进8个字节。这主要是因为堆栈在内部以16字节为增量进行计数,并且没有使用不符合RFC标准的长度值的处理代码。这种不匹配导致堆栈将当前选项的最后8个字节解释为第二个选项的开始,最终导致缓冲区溢出和潜在的RCE。四、利用思路1、利用条件基本条件攻击者需要获取目标的IPv6和MAC地址才能触发该过程。攻击者需要配合其他内存泄漏或信息泄漏漏洞来实现RCE。攻击者需要想办法绕过tcpip.sys的GS保护机制2.利用过程攻击者直接向目标发送特制的ICMPv6路由广播包:[攻击者]3.攻击向量建立连接后,使用IPv6直接发送攻击包。5.流量分析由于该漏洞直接利用了IPv6,一些部署在IP层之上的防火墙方案无法对该漏洞进行流量检测,但是带有IP层流量检测的防火墙可以轻松检测到恶意流量:在流量中可以很明显的看到地址第一个Option结构的字段误识别并计算出一个RecursiveDNSServer的值:第一个RecursiveDNSServer的地址是0018-0027,后面的8个字节应该不会再被识别。WhenthesecondRecursiveDNSServerisselected,thesituationisasfollows:theaddressofthesecondRecursiveDNSServeris0028-0037.但是这16个字节的最后8个字节显然是下一个ICMPv6Option结构的内容:4.参考https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898https://tools.ietf.org/html/rfc8106https://www.mcafee.com/blogs/other-blogs/mcafee-labs/cve-2020-16898-bad-neighbor/
