![Windows TCP/IP远程执行代码漏洞分析](http://img.jiangsulong.com/220422/1SJ1FN-0.jpg)
文章插图
报告编号:B6-2020-101901
报告来源:360-CERT
报告作者:360-CERT
更新日期:2020-10-19
0x01 前言1.1 环境搭建
(1)攻击机环境:Ubuntu 20.04
安装scapy
sudo apt install Python-pip3sudo pip3 install scapy
(2)受害机环境:windows 10 1909 x64tcpip.sys 驱动版本:10.0.18362.476
(3)双机调试Windows 驱动:
https://blog.csdn.net/qq_21000273/article/details/52027708
断点:
bp tcpip!Ipv6pUpdateRDNSSbp tcpip!Ipv6pHandleRouterAdvertisementbp tcpip!Ipv6pHandleRouterAdvertisement+0xae4ccbp tcpip!Ipv6pHandleRouterAdvertisement+0xae4dbbp tcpip!Ipv6pUpdateRDNSS+0x99bp tcpip!Ipv6pUpdateRDNSS+0xca
1.2 背景知识涉及的包类型:
type:24Route Information Optiontype:25Recursive DNS Server Optiontype:134IMCPv6 Router Advertisement
涉及的结构:_MDL结构
typedef __struct_bcount (Size ) struct _MDL {struct _MDL *Next ;CSHORT Size ;CSHORT MdlFlags ;struct _EPROCESS *Process ;PVOID MAppedSystemVa ;PVOID StartVa ;ULONG ByteCount ;ULONG ByteOffset ;} MDL , *PMDL ;
_NET_BUFFER 结构typedef struct _NET_BUFFER {union {struct {PNET_BUFFER Next;PMDLCurrentMdl;ULONGCurrentMdlOffset;union {ULONGDataLength;SIZE_T stDataLength;};PMDLMdlChain;ULONGDataOffset;};SLIST_HEADERLink;NET_BUFFER_HEADER NetBufferHeader;};USHORTChecksumBias;USHORTReserved;NDIS_HANDLENdisPoolHandle;PVOIDNdisReserved[2];PVOIDProtocolReserved[6];PVOIDMiniportReserved[4];NDIS_PHYSICAL_ADDRESS DataPhysicalAddress;union {PNET_BUFFER_SHARED_MEMORY SharedMemoryInfo;PSCATTER_GATHER_LISTScatterGatherList;};} NET_BUFFER, *PNET_BUFFER;
相关函数:NdisGetDataBuffer 函数
PVOID NdisGetDataBuffer(PNET_BUFFER NetBuffer,ULONGBytesNeeded,PVOIDStorage,UINTAlignMultiple,UINTAlignOffset);
NetBuffer:指向NET_BUFFER 结构的指针BytesNeeded:请求的连续数据的字节数
Storage:指向缓冲区的指针,如果调用者未提供缓冲区,则为NULL 。缓冲区的大小必须大于或等于BytesNeeded中指定的字节数 。如果此值为非NULL,并且请求的数据不连续,则NDIS将请求的数据将复制到Storage指向的地址 。
Windows通过Ipv6pHandleRouterAdvertisement 函数处理 IPv6 路由器通告数据,在该函数中调用 NdisGetDataBuffer 函数从 NET_BUFFER 结构中访问连续或不连续的数据,通过 NET_BUFFER ->CurrentMdlOffset 字段来记录要访问数据起始地址相对于_MDL->MappedSystemVa 的偏移 。
0x02 漏洞分析2.1 漏洞背景
2020年10月14日,360CERT监测发现 Microsoft 发布了 TCP/IP远程代码执行漏洞 的风险通告,该漏洞是由于Windows TCP/IP堆栈 在处理IMCPv6 Router Advertisement(路由通告)数据包时存在漏洞,远程攻击者通过构造特制的ICMPv6 Router Advertisement(路由通告)数据包,并将其发送到远程Windows主机上,可造成远程BSOD,漏洞编号为CVE-2020-16898 。
2.2 漏洞成因
根据rfc5006 描述,RDNSS包的length应为奇数,而当攻击者构造的RDNSS包的Length为偶数时,Windows TCP/IP 在检查包过程中会根据Length来获取每个包的偏移,遍历解析,导致对 Addresses of IPv6 Recursive DNS Servers 和下一个 RDNSS 选项的边界解析错误,从而绕过验证,将攻击者伪造的option包进行解析,造成栈溢出,从而导致系统崩溃 。
RDNSS Option 数据包格式如下:
![Windows TCP/IP远程执行代码漏洞分析](http://img.jiangsulong.com/220422/1SJ11119-1.jpg)
文章插图
Type: 占8-bit,RDNSS 的类型为25
Length:8-bit无符号整数,单位长度为8个字节,所以Type, Length, Reserved, Lifetime一共占8个字节,一个单位长度,而一个IPv6地址占16个字节,两个单位长度,所以Length的最小值为3,且为奇数 。
Reserved:保留字段
Lifetime:32-bit无符号整数,存活周期 。
Addresses of IPv6 Recursive DNS Servers:保存RNDSS的IPv6地址,每个占16个字节,地址的数量会影响Length字段,number=(Length - 1) / 2 。每增加一个地址,Length加2 。
漏洞点存在于tcpip.sys -> Ipv6pHandleRouterAdvertisement 函数
漏洞调用链为:Icmpv6ReceiveDatagrams -> Ipv6pHandleRouterAdvertisement -> Ipv6pUpdateRDNSS
【Windows TCP/IP远程执行代码漏洞分析】Ipv6pHandleRouterAdvertisement 函数存在两个循环,第一个循环遍历所有headers,做一些基本的验证,如length的大小,第二个循环用于处理包,并且该阶段不再验证,两个循环的伪代码如下:
// 循环1while ( 1 ){……v28 = (KIRQL *)NdisGetDataBuffer(v9, 2u, v182, 1u, 0);v27 = v9->DataLength;actual_length_bytes = 8 * v28[1];……switch ( v25 ){case 0x18u:// case 0x18 (ICMPv6NDOptRouteInfo)……if ( actual_length_bytes > 0x18u|| (v144 = *((_BYTE *)NdisGetDataBuffer(v9, actual_length_bytes, v220, 1u, 0) + 2), v144 > 0x80u)|| v144 > 0x40u && actual_length_bytes < 0x18u// <-----【1】验证实际字节数,不能大于0x18|| v144 && actual_length_bytes < 0x10u ){*a3 = 24;goto LABEL_275;}break;case 0x19u:// case 0x19 (ICMPv6NDOptRDNSS)// <-----【2】if ( (*(_BYTE *)(v11 + 404) & 0x40) != 0 && actual_length_bytes < 0x18u )*a3 = 25;break;}……if ( actual_length_bytes ){v31 = actual_length_bytes + v9->CurrentMdlOffset;if ( v31 >= *(_Dword *)(v9->Link.Region + 0x28) ){NdisAdvanceNetBufferDataStart(v9, actual_length_bytes, 0, 0i64);// <---actual_length_bytes=4*8=0x20}else{v9->DataOffset += actual_length_bytes;v9->DataLength -= actual_length_bytes;v9->CurrentMdlOffset = v31;// 更新CurrentMdlOffset}}v21 += actual_length_bytes;}……// 循环2 while ( 1 ){……if ( *v75 == 0x18 )// case 0x18 (ICMPv6NDOptRouteInfo){……v153 = (unsigned __int8 *)NdisGetDataBuffer(NetBuffer_1, actual_option, Storage_1, 1u, 0); // <--- 【3】v225 = _mm_load_si128((const __m128i *)&_xmm);v174 = v225.m128i_u32[((unsigned __int64)v153[3] >> 3) & 3];……}if ( *v75 == 0x19 )// case 0x19 (ICMPv6NDOptRDNSS){if ( (*(_BYTE *)(v11 + 0x194) & 0x40) != 0 ){Ipv6pUpdateRDNSS(v11, NetBuffer_1, Buf2, v189, &v170);// <---- 【4】goto LABEL_309;}}else if ( *v75 == 31 && (*(_BYTE *)(v11 + 404) & 0x40) != 0 ){Ipv6pUpdateDNSSL(v11, NetBuffer_1, Buf2, (unsigned int)v189, &v170);LABEL_309:v77 = v166;goto LABEL_118;}……}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 为什么 TCP 协议有粘包问题
- 物联网网关搭建VPN客户端,来实现PLC远程下载
- 从一个HTTP请求来读懂HTTP、TCP协议
- TCP/IP协议 网络层
- 系统小技巧:日夜分明 Windows 10主题模式自动换
- TCP 粘包、半包 Netty 全搞定
- windows电脑如何快速截屏截图?电脑如何快速屏幕截图?
- 想做物联网远程控制却没有服务器?这里教你“白嫖”一个
- 手把手教你0基础安装windows系统,丰富图文包教包会
- 卸掉“赘肉”让Windows轻松前进