報告編號:B6-2020-101901
報告來源:360-CERT
報告作者:360-CERT
更新日期:2020-10-19
0x01 前言
1.1 環(huán)境搭建
(1)攻擊機環(huán)境:Ubuntu 20.04
安裝scapy
sudoapt install python-pip3sudopip3 install scapy
(2)受害機環(huán)境:Windows 10 1909 x64
tcpip.sys 驅(qū)動版本:10.0.18362.476
(3)雙機調(diào)試Windows 驅(qū)動:
https://blog.csdn.net/qq_21000273/article/details/52027708
斷點:
bptcpip!Ipv6pUpdateRDNSSbptcpip!Ipv6pHandleRouterAdvertisementbptcpip!
Ipv6pHandleRouterAdvertisement+0xae4ccbptcpip!Ipv6pHandleRouterAdvertisement+0xae4dbbptcpip!Ipv6pUpdateRDNSS+0x99bptcpip!Ipv6pUpdateRDNSS+0xca
1.2 背景知識
涉及的包類型:
type:24 Route Information Optiontype:25
Recursive DNS Server Optiontype:134 IMCPv6 Router Advertisement
涉及的結(jié)構(gòu):
_MDL結(jié)構(gòu)
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 結(jié)構(gòu)
typedefstruct _NET_BUFFER {union{struct{PNET_BUFFERNext;
PMDLCurrentMdl;ULONGCurrentMdlOffset;union{ULONGDataLength;SIZE_TstDataLength;};PMDLMdlChain;ULONGDataOffset;};SLIST_HEADERLink;NET_BUFFER_HEADERNetBufferHeader;};USHORTChecksumBias;USHORTReserved;NDIS_HANDLENdisPoolHandle;PVOIDNdisReserved[2];PVOIDProtocolReserved[6];PVOIDMiniportReserved[4];NDIS_PHYSICAL_ADDRESSDataPhysicalAddress;union{PNET_BUFFER_SHARED_MEMORYSharedMemoryInfo;PSCATTER_GATHER_LISTScatterGatherList;};}NET_BUFFER, *PNET_BUFFER;
相關(guān)函數(shù):
NdisGetDataBuffer 函數(shù)
PVOIDNdisGetDataBuffer(PNET_BUFFERNetBuffer,ULONGBytesNeeded,
PVOIDStorage,UINTAlignMultiple,UINTAlignOffset);
NetBuffer:指向NET_BUFFER 結(jié)構(gòu)的指針
BytesNeeded:請求的連續(xù)數(shù)據(jù)的字節(jié)數(shù)
Storage:指向緩沖區(qū)的指針,如果調(diào)用者未提供緩沖區(qū),則為NULL。緩沖區(qū)的大小必須大于或等于BytesNeeded中指定的字節(jié)數(shù)。如果此值為非NULL,并且請求的數(shù)據(jù)不連續(xù),則NDIS將請求的數(shù)據(jù)將復(fù)制到Storage指向的地址。
Windows通過Ipv6pHandleRouterAdvertisement 函數(shù)處理 IPv6 路由器通告數(shù)據(jù),在該函數(shù)中調(diào)用 NdisGetDataBuffer 函數(shù)從 NET_BUFFER 結(jié)構(gòu)中訪問連續(xù)或不連續(xù)的數(shù)據(jù),通過 NET_BUFFER ->CurrentMdlOffset 字段來記錄要訪問數(shù)據(jù)起始地址相對于_MDL->MappedSystemVa 的偏移。
0x02 漏洞分析
2.1 漏洞背景
2020年10月14日,360CERT監(jiān)測發(fā)現(xiàn) Microsoft 發(fā)布了 TCP/IP遠(yuǎn)程代碼執(zhí)行漏洞 的風(fēng)險通告,該漏洞是由于Windows TCP/IP堆棧 在處理IMCPv6 Router Advertisement(路由通告)數(shù)據(jù)包時存在漏洞,遠(yuǎn)程攻擊者通過構(gòu)造特制的ICMPv6 Router Advertisement(路由通告)數(shù)據(jù)包 ,并將其發(fā)送到遠(yuǎn)程Windows主機上,可造成遠(yuǎn)程BSOD,漏洞編號為CVE-2020-16898。
2.2 漏洞成因
根據(jù)rfc5006 描述,RDNSS包的length應(yīng)為奇數(shù),而當(dāng)攻擊者構(gòu)造的RDNSS包的Length為偶數(shù)時,Windows TCP/IP 在檢查包過程中會根據(jù)Length來獲取每個包的偏移,遍歷解析,導(dǎo)致對 Addresses of IPv6 Recursive DNS Servers 和下一個 RDNSS 選項的邊界解析錯誤,從而繞過驗證,將攻擊者偽造的option包進行解析,造成棧溢出,從而導(dǎo)致系統(tǒng)崩潰。
RDNSS Option 數(shù)據(jù)包格式如下:
Type: 占8-bit,RDNSS 的類型為25
Length:8-bit無符號整數(shù),單位長度為8個字節(jié),所以Type, Length, Reserved, Lifetime一共占8個字節(jié),一個單位長度,而一個IPv6地址占16個字節(jié),兩個單位長度,所以Length的最小值為3,且為奇數(shù)。
Reserved:保留字段
Lifetime:32-bit無符號整數(shù),存活周期。
Addresses of IPv6 Recursive DNS Servers:保存RNDSS的IPv6地址,每個占16個字節(jié),地址的數(shù)量會影響Length字段,number=(Length - 1) / 2。每增加一個地址,Length加2。
漏洞點存在于tcpip.sys -> Ipv6pHandleRouterAdvertisement 函數(shù)
漏洞調(diào)用鏈為:Icmpv6ReceiveDatagrams -> Ipv6pHandleRouterAdvertisement -> Ipv6pUpdateRDNSS
Ipv6pHandleRouterAdvertisement 函數(shù)存在兩個循環(huán),第一個循環(huán)遍歷所有headers,做一些基本的驗證,如length的大小,第二個循環(huán)用于處理包,并且該階段不再驗證,兩個循環(huán)的偽代碼如下:
//循環(huán)1while(1){……v28=(KIRQL*)NdisGetDataBuffer(v9,2u,v182,1u,0);
v27=v9->DataLength;actual_length_bytes=8*v28[1];……switch(v25){case 0x18u://case0x18(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】驗證實際字節(jié)數(shù),不能大于0x18||v144&&actual_length_bytes<0x10u){*a3=24;gotoLABEL_275;}break;case 0x19u://case0x19(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;}……//循環(huán)2while(1){……if(*v75==0x18)//case0x18(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)//xffffeaeaBUFFER41414141字節(jié)