SMBv3遠(yuǎn)程拒絕服務(wù)(BSOD)漏洞分析
前言
這個(gè)SMBv3漏洞是由lgandx爆出的一個(gè)未被微軟修復(fù)的漏洞(暫未發(fā)布補(bǔ)丁),漏洞出來后我進(jìn)行了一定的分析,花了很多時(shí)間,這個(gè)漏洞有一些意思,但是對(duì)于SMB的整個(gè)協(xié)議通信過程非常龐大,所以沒有進(jìn)行非常細(xì)致的跟蹤,包括一些不透明的結(jié)構(gòu)體讓我感到暈頭轉(zhuǎn)向,但到最后還是有了一些結(jié)果。
這個(gè)SMB漏洞可以看作是被動(dòng)的,需要用戶主動(dòng)去訪問445端口才可以觸發(fā),而不像ms08067一樣主動(dòng)攻擊別人,所以需要運(yùn)行漏洞腳本在操作系統(tǒng)上。
那么很多人看到PoC中的關(guān)鍵部分,就會(huì)想:有填充數(shù)據(jù),會(huì)不會(huì)是緩沖區(qū)溢出!
- ## Tree Connect
 - if data[16:18] == "\x03\x00":
 - head = SMBv2Header(Cmd="\x03\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", TID="\x01\x00\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x00\x00\x00\x00", SessionID=GrabSessionID(data))
 - t = SMB2TreeData(Data="C"*1500)#//BUG
 - packet1 = str(head)+str(t)
 - buffer1 = longueur(packet1)+packet1
 - print "[*]Triggering Bug; Tree Connect SMBv2 packet sent."
 - self.request.send(buffer1)
 - data = self.request.recv(1024)
 
答案是否定的,至少在我看來,大量的數(shù)據(jù)目的并非是為了填充緩沖區(qū),而是為了繞過tcpip.sys的某處判斷,從而進(jìn)入漏洞出發(fā)的函數(shù)調(diào)用邏輯。
問題出現(xiàn)在smbv2后的一個(gè)特性Tree Connect,用來處理共享服務(wù)的特性,opcode:0x03,而整個(gè)問題,確是多個(gè)地方導(dǎo)致的。下面我們就一起來進(jìn)入今天的旅程吧!
Github地址:https://github.com/lgandx/PoC/tree/master/SMBv3%20Tree%20Connect
漏洞復(fù)現(xiàn)
首先,網(wǎng)上關(guān)于這個(gè)漏洞的觸發(fā)方法有很多,比較通用的是twitter中某老外提到的Powershell的方法,最為簡(jiǎn)單,首先我們調(diào)試的環(huán)境是:Windows 10 x64 build 1607

接下來我們?cè)趉ali2.0里運(yùn)行漏洞腳本。
隨后執(zhí)行"dir \ip\PATH",漏洞觸發(fā),通過windbg雙機(jī)聯(lián)調(diào),此時(shí)捕捉到了BSOD。
可以看到提示此時(shí)問題出現(xiàn)在mrxsmb20.sys中,問題函數(shù)是Smb2ValidateNegotiateInfo,來看一下觸發(fā)位置的代碼。
- kd> p
 - mrxsmb20!Smb2ValidateNegotiateInfo+0x17:
 - fffff803`1869c7d7 66394114 cmp word ptr [rcx+14h],ax
 - kd> r rcx
 - rcx=0x00000000`00000000
 
此時(shí)rcx的值為0x0,是一處無效地址,因此這是由于空指針引用導(dǎo)致的BSOD,接下來繼續(xù)執(zhí)行可以看到Windows 10引發(fā)藍(lán)屏。
回溯及數(shù)據(jù)包分析(important!)
我們來看一下mrxsmb20.sys關(guān)于Tree Connect特性的一些內(nèi)容,代碼邏輯相對(duì)簡(jiǎn)單。
可以看到執(zhí)行到Smb2ValidateNegotiateInfo函數(shù)有兩條邏輯調(diào)用,一個(gè)是Smb2TreeConnect_CopyData,一個(gè)是Smb2TreeConnect_Receive,這里我就把我回溯的結(jié)果和大家分享一下,首先,通過Smb2TreeConnect_Receive來接收smb的Tree Connect數(shù)據(jù),這個(gè)是通過opcode來決定的。
正常情況下不會(huì)進(jìn)入Smb2TreeConnect_CopyData,但一旦由不正常(后面會(huì)提到)數(shù)據(jù)包執(zhí)行,則會(huì)在Receive之后進(jìn)入CopyData函數(shù)的處理邏輯,從而引發(fā)漏洞。
這里數(shù)據(jù)包分析很關(guān)鍵,因?yàn)樵诼┒从|發(fā)過程中,就是由于數(shù)據(jù)包的問題導(dǎo)致的。
來看一下Smb最關(guān)鍵的這個(gè)數(shù)據(jù)包。
來看一下Smb頭部的協(xié)議格式。

在協(xié)議格式中Opcode指示smb類型
注意數(shù)據(jù)包中對(duì)應(yīng)位置,opcode值是0x03,就是tree connect的處理。同時(shí)這里在后面分析中我們要用到,注意Data數(shù)據(jù)之前的長(zhǎng)度。其中包含了NetBIOS Session Service 4字節(jié),和 SMB2 Header + Tree Connect Body 80字節(jié),以及 Data n字節(jié)。這個(gè)非常重要,后續(xù)分析我們會(huì)用到。
漏洞分析
剛開始,我天真的以為是CopyData引發(fā)的某些異常,后來發(fā)現(xiàn)我錯(cuò)了,其實(shí)這個(gè)漏洞可以看成利用tcpip.sys中的某些邏輯特性,以及mrxsmb20.sys中對(duì)于相關(guān)結(jié)構(gòu)的檢查不夠嚴(yán)格導(dǎo)致的空指針引用BSOD,而整個(gè)漏洞形成,我是利用正常和不正常的對(duì)比才終于發(fā)現(xiàn)。在分析的過程中,大量不透明的結(jié)構(gòu)體引用讓我有點(diǎn)尷尬,期待更熟悉SMB的大牛能夠繼續(xù)豐富分析。
正常的SMB2 Tree Connect包是不會(huì)觸發(fā)異常的。
首先我們來看一下正常的邏輯調(diào)用,關(guān)鍵函數(shù)在tcpip.sys中的TcpDeliverDataToClient,這個(gè)函數(shù)負(fù)責(zé)處理接收到的數(shù)據(jù)包,在一個(gè)while(1)循環(huán)中。
- char __fastcall TcpDeliverDataToClient(PKSPIN_LOCK SpinLock, KSPIN_LOCK *a2, _QWORD *a3, _QWORD **a4)
 - {
 - while ( 1 )
 - {
 - ……
 - v22 = (unsigned int)vars30;
 - v23 = TcpIndicateData(v7, v6, v5, &v72);
 - v24 = v71;
 - if ( !(v6[3] + v6[4]) )
 - break;
 - ……
 
在這個(gè)循環(huán)中,剛進(jìn)入循環(huán)位置有一個(gè)if語句,后面我們會(huì)提到,在接收到TreeConnect包之后,不會(huì)進(jìn)入if語句,而是執(zhí)行下面的函數(shù)調(diào)用,在TcpIndicateData函數(shù)內(nèi)部會(huì)調(diào)用到之前提到的Smb2TreeConnect_Receive,注意這一切現(xiàn)在都是在我們發(fā)送一個(gè)正常數(shù)據(jù)包時(shí)完成的。(接下來我們會(huì)分析到為什么是正常的)
在這個(gè)函數(shù)入口下條件斷點(diǎn)。
- kd> bp tcpip!TcpDeliverDataToClient ".if(poi(rbx+20)==0x1E4){;}.else{g;}"
 - kd> g
 - tcpip!TcpDeliverDataToClient:
 - fffff801`f18017a0 4055 push rbp
 - kd> dd rbx+20 L1
 - ffffb304`06865c58 000001e4
 
命中時(shí),rbx會(huì)存放一個(gè)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體按照IDA的反饋來看是一個(gè)KSPIN_LOCK自旋鎖,windows內(nèi)核同步處理的一種機(jī)制,這個(gè)暫且不管,注意一下rbx結(jié)構(gòu)體+20位置的值,是1e4,這個(gè)值轉(zhuǎn)換成10進(jìn)制就是484,正好是我們發(fā)送的400個(gè)C的Data數(shù)據(jù)加剛才我們提到的頭部84字節(jié)的長(zhǎng)度。
接下來進(jìn)入TcpIndicateData函數(shù)后會(huì)命中Smb2TreeConnect_Receive函數(shù)開始進(jìn)行接收處理。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x209:
 - fffff801`f18019a9 e8e2810100 call tcpip!TcpIndicateData (fffff801`f1819b90)
 - kd> dd rbx
 - ffffb304`06865c38 aa9ce398 fffff801 00000000 00000000
 - ffffb304`06865c48 00000000 00000000 00000000 00000000
 - ffffb304`06865c58 000001e4 00000000 00000000 00000000
 - ffffb304`06865c68 00000000 00000000 00000000 00000000
 - ffffb304`06865c78 06865c60 ffffb304 00000000 00000000
 - ffffb304`06865c88 00000000 00000000 00000000 00000000
 - ffffb304`06865c98 00000000 00000000 00000000 00000000
 - ffffb304`06865ca8 00000000 00000000 00000000 00000001
 - kd> p
 - Breakpoint 1 hit
 - mrxsmb20!Smb2TreeConnect_Receive:
 - fffff801`f3fbc4b0 48895c2420 mov qword ptr [rsp+20h],rbx
 
處理過程很長(zhǎng),這里我直接略過,在處理結(jié)束后會(huì)多層ret后返回到TcpDeliverDataToClient函數(shù)中,仍然處于while循環(huán)中。
- kd> bp tcpip!TcpIndicateData+0x268
 - kd> g
 - Breakpoint 3 hit
 - tcpip!TcpIndicateData+0x268:
 - fffff80a`72c39df8 c3 ret
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x20e:
 - fffff80a`72c219ae 833defa51a0001 cmp dword ptr [tcpip!MICROSOFT_TCPIP_PROVIDER_Context+0x24 (fffff80a`72dcbfa4)],1
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x215:
 - fffff80a`72c219b5 448bf0 mov r14d,eax
 
這里我列舉一下返回過程的逐層調(diào)用邏輯,因?yàn)閗b回溯不到。Smb2TreeConnect_Receive -> SmbReceiveInd -> VctIndRecv -> SmbWskReceiveEvent -> afd!WskProTLEventReceive -> tcpip!TcpIndicateData -> tcpip!TcpDeliverDataToClient。
接下來就是關(guān)鍵了,首先會(huì)執(zhí)行一處sub匯編指令。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x2b9:
 - fffff80a`72c21a59 48297b20 sub qword ptr [rbx+20h],rdi
 - kd> r rdi
 - rdi=00000000000001e4
 - kd> dd rbx+20 L1
 - ffffc10c`9fe79e78 000001e4
 
這個(gè)相減之后,會(huì)將rbx結(jié)構(gòu)體對(duì)應(yīng)的長(zhǎng)度變成0,隨后,會(huì)到達(dá)一處cmp操作,這處cmp操作會(huì)將這個(gè)值作為一個(gè)判斷條件。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x2de:
 - fffff80a`72c21a7e 4c896b48 mov qword ptr [rbx+48h],r13
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x2e2:
 - fffff80a`72c21a82 488b4320 mov rax,qword ptr [rbx+20h]
 - kd> dd rbx+18 L1
 - ffffc10c`9fe79e70 00000000
 - kd> dd rbx+20 L1
 - ffffc10c`9fe79e78 00000000
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x2e6:
 - fffff80a`72c21a86 48034318 add rax,qword ptr [rbx+18h]
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x2ea:
 - fffff80a`72c21a8a 0f858dfeffff jne tcpip!TcpDeliverDataToClient+0x17d (fffff80a`72c2191d)
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x2f0:
 - fffff80a`72c21a90 48837e2000 cmp qword ptr [rsi+20h],0
 
來看一下這一段偽代碼。
- while ( 1 )
 - {
 - v70 = v10;
 - v69 = TcpSatisfyReceiveRequests(v7);
 - if ( v24 >= v23 )
 - {
 - }
 - else
 - {
 - v25 = (char *)ReceiveDpcTable + 24 * v21;
 - v26 = v23 - v24;
 - v27 = v7[2];
 - v70 = v26;
 - *(_QWORD *)(*(_QWORD *)(v27 + 128) + (v21 << 7) + 56) -= v24;
 - v28 = *((_DWORD *)v25 + 5);
 - if ( v28 & 1 )
 - *((_DWORD *)v25 + 5) = v28 | 4;
 - else
 - TcpStartRcvWndTuningTimer(vars38);
 - v6[4] -= v26;
 - v29 = v6[9];
 - v6[3] = 0i64;
 - if ( v26 + v29 )
 - {
 - TcpAdvanceTcbRcvWnd(v7, (unsigned int)(v26 + *((_DWORD *)v6 + 18)));
 - v6[9] = 0i64;
 - }
 - else
 - {
 - v6[9] = 0i64;
 - }
 - }
 - if ( !(v6[3] + v6[4]) )
 - break;
 
在偽代碼最后的位置,會(huì)對(duì)兩個(gè)值進(jìn)行判斷,如果兩個(gè)值之和為0,則條件成立,程序會(huì)跳出循環(huán),剛才的跟蹤我們可以發(fā)現(xiàn),v6就是結(jié)構(gòu)體,v6[4]的值來源于它自身減v26,而v26就是它自身,最后它的值為0,而剛才跟蹤v6[3]的值也為0(如果知道結(jié)構(gòu)體就好清楚v6到底是什么了T.T)。
經(jīng)過對(duì)比調(diào)試,發(fā)現(xiàn)在正常的處理SMB Tree Connect包和觸發(fā)BSOD的不正常情況下有一處關(guān)鍵的跳轉(zhuǎn)邏輯,這里是一處if語句判斷,成立則break跳出while循環(huán),不成立,會(huì)繼續(xù)執(zhí)行。
那么不正常的情況呢?之前的處理和之前的分析一樣,我們加大Data的值到1200,但是在返回后。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x2b9:
 - fffff80a`72c21a59 48297b20 sub qword ptr [rbx+20h],rdi
 - kd> r rdi
 - rdi=0000000000000404
 - kd> dd rbx+20
 - ffffc10c`a0643e78 00000504
 
顯而易見,在我們加大Data長(zhǎng)度的時(shí)候,到相減位置結(jié)構(gòu)體對(duì)應(yīng)位置的值是504,也就是1284,正好是Data的長(zhǎng)度1200字節(jié) + 剛才分析到的84字節(jié),而此時(shí)rdi的值只有0x404,也就是944長(zhǎng)度,這是一個(gè)Max值,如果Data長(zhǎng)度超過0x404,這里會(huì)認(rèn)為還有數(shù)據(jù),因此相減后v6[4]的值不為0。
也就是說在SMB Tree Connect數(shù)據(jù)交互過程中,TcpDeliverDataToClient中關(guān)于這個(gè)地方的邏輯處理是,會(huì)根據(jù)數(shù)據(jù)包的長(zhǎng)度,如果數(shù)據(jù)包長(zhǎng)度小于0x404,則相減時(shí)v26的值是長(zhǎng)度本身,然后會(huì)break。如果數(shù)據(jù)包長(zhǎng)度大于0x404,則v26的值為max值,也就是0x404,相減不為0,則不會(huì)break。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x2bd:
 - fffff80a`72c21a5d 4533ed xor r13d,r13d
 - kd> dd rbx+20
 - ffffc10c`a0643e78 00000100
 
這造成了一個(gè)問題,就是剛才到的break位置由于v6[4]不為0,所以不執(zhí)行break,而是進(jìn)入后續(xù)的處理。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x2e2:
 - fffff80a`72c21a82 488b4320 mov rax,qword ptr [rbx+20h]
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x2e6:
 - fffff80a`72c21a86 48034318 add rax,qword ptr [rbx+18h]
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x2ea:
 - fffff80a`72c21a8a 0f858dfeffff jne tcpip!TcpDeliverDataToClient+0x17d (fffff80a`72c2191d)
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x17d:
 - fffff80a`72c2191d 49833f00 cmp qword ptr [r15],0
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x181:
 - fffff80a`72c21921 0f85e9010000 jne tcpip!TcpDeliverDataToClient+0x370 (fffff80a`72c21b10)
 
接下來,程序會(huì)回到while入口位置,接下來會(huì)進(jìn)入之前提到?jīng)]有進(jìn)入的if語句處理,這是由于剛才沒有break結(jié)束循環(huán)的原因,此時(shí)會(huì)進(jìn)入if語句的處理,函數(shù)中所調(diào)用的函數(shù)都是Complete,猜測(cè)都是和結(jié)束數(shù)據(jù)包相關(guān)處理有關(guān)。
- kd> p
 - tcpip!TcpDeliverDataToClient+0x1c1:
 - fffff80a`72c21961 e99bfeffff jmp tcpip!TcpDeliverDataToClient+0x61 (fffff80a`72c21801)
 - kd> p
 - tcpip!TcpDeliverDataToClient+0x61:
 - fffff80a`72c21801 48837b0800 cmp qword ptr [rbx+8],0
 - kd> dd rbx+8
 - ffffc10c`a0643e60 9d8c2fa0 ffffc10c 9d8c2fa0 ffffc10c
 
來看一下這個(gè)if語句。
- while ( 1 )
 - {
 - if ( v6[1] )
 - {
 - if ( !*v5 )
 - break;
 - v9 = v6[1];
 - v10 = v6[2];
 - *((_BYTE *)v6 + 98) &= 0xFEu;
 - v69 = v9;
 - v6[1] = 0i64;
 - v6[2] = 0i64;
 - v11 = vars30;
 - v71 = v10;
 - LODWORD(v12) = TcpSatisfyReceiveRequests(v7, 0, (__int64)v6, vars30, v5, &v69, &v66);
 - }
 - }
 
在這個(gè)if語句中,會(huì)調(diào)用TcpSatisfyReceiveRequests函數(shù),這個(gè)函數(shù)中第六個(gè)參數(shù),也就是v69是很關(guān)鍵的,這個(gè)值決定了后面的空指針引用,接下來進(jìn)入這個(gè)函數(shù)。
- int __fastcall TcpSatisfyReceiveRequests(PKSPIN_LOCK SpinLock, char a2, __int64 a3, signed int a4, __int64 *a5, __int64 *a6, _DWORD *a7)
 - {
 - v8 = *a5;
 - v95 = SpinLock;
 - v9 = *a6; // RBP+148
 - v38 = *(_QWORD *)(v9 + 48);
 - v39 = *(_QWORD *)(v9 + 56);
 - v40 = *(_QWORD *)(v9 + 8);
 - v41 = *(_QWORD *)(v9 + 72);
 - v93 += v38;
 - v99 += *(_QWORD *)(v9 + 40);
 - v42 = *(_QWORD *)v9;
 - _guard_dispatch_icall_fptr(v40, 0i64, v38, v39);// call WskProTLReceiveComplete
 
這個(gè)函數(shù)中的_guard_dispatch_icall_fptr調(diào)用了WskProTLreceiveComplete函數(shù),而v40參數(shù)和v9結(jié)構(gòu)體有關(guān),v9是由傳入第六個(gè)參數(shù),也就是剛才提到的v69有關(guān),v69又來自于v6[1],而這個(gè)結(jié)構(gòu)體是和Complete有關(guān),但是在TreeConnect數(shù)據(jù)包中卻沒有對(duì)這個(gè)結(jié)構(gòu)體進(jìn)行賦值。
隨后在WskProTLReceiveComplete中,會(huì)將rcx,也就是第一個(gè)參數(shù)v40,進(jìn)行傳遞(64位Windows系統(tǒng)中,參數(shù)傳遞通過寄存器,第一個(gè)參數(shù)是rcx,第二個(gè)是rdx,第三個(gè)是r8,第四個(gè)是r9)。在后面的分析中,省略了無關(guān)的匯編過程,只留關(guān)鍵的給大家分享。
- kd> p
 - afd!WskProTLReceiveComplete+0x34:
 - fffff80a`7365aa84 488bd9 mov rbx,rcx
 - …………
 - kd> p
 - afd!WskProTLReceiveComplete+0x8e:
 - fffff80a`7365aade 488bcb mov rcx,rbx
 - kd> r rbx
 - rbx=ffffc10ca01ba010
 - kd> p
 - afd!WskProTLReceiveComplete+0x91:
 - fffff80a`7365aae1 ff15512d0200 call qword ptr [afd!_imp_IofCompleteRequest (fffff80a`7367d838)]
 
經(jīng)過一系列傳遞后,這個(gè)第一個(gè)參數(shù)會(huì)直接傳給IofCompleteRequest函數(shù),這個(gè)函數(shù)是irp完成函數(shù),其實(shí)是一個(gè)中間過程,同步irp完成,后面就是善后工作。
在函數(shù)中,參數(shù)繼續(xù)傳遞。
- kd> p
 - nt!IopfCompleteRequest+0xb:
 - fffff800`9464b81b 4881ec00010000 sub rsp,100h
 - kd> p
 - nt!IopfCompleteRequest+0x12:
 - fffff800`9464b822 488bd9 mov rbx,rcx
 - …………
 - kd> p
 - nt!IopfCompleteRequest+0x109:
 - fffff800`9464b919 488bd3 mov rdx,rbx
 - kd> p
 - nt!IopfCompleteRequest+0x10c:
 - fffff800`9464b91c 488bce mov rcx,rsi
 - kd> p
 - nt!IopfCompleteRequest+0x10f:
 - fffff800`9464b91f ff5735 call qword ptr [rdi+35h]
 - kd> t
 - Breakpoint 0 hit
 - mrxsmb!SmbWskReceiveComplete:
 - fffff80a`731d6950 48895c2408 mov qword ptr [rsp+8],rbx
 
在IofCompleteRequest函數(shù)中,會(huì)有一處調(diào)用回到SmWskReceivComplete函數(shù),而結(jié)構(gòu)體會(huì)交給rdx,也就是第二個(gè)參數(shù)進(jìn)入這個(gè)函數(shù)。隨后這個(gè)參數(shù)會(huì)連續(xù)傳遞。先來看一下之前的堆?;厮?。
- kd> kb
 - RetAddr : Args to Child : Call Site
 - fffff800`9464b922 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : mrxsmb!SmbWskReceiveComplete
 - fffff80a`7365aae7 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!IopfCompleteRequest+0x112
 - fffff80a`72c60d9d : fffff800`963d54a8 ffffc10c`9ed02780 fffff800`963d54b0 fffff800`963d547c : afd!WskProTLReceiveComplete+0x97
 - fffff80a`72c21860 : 00000000`00000002 ffffc10c`a0643d00 00000000`00000007 00000000`00000000 : tcpip!TcpSatisfyReceiveRequests+0x3cd
 - 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : tcpip!TcpDeliverDataToClient+0xc0
 
之后參數(shù)會(huì)連續(xù)進(jìn)行傳遞,首先會(huì)把當(dāng)前rdx+b8存放的值交給r14,之后把r14+40位置的值交給r8,最后引用的就是r8+98位置的值。
- kd> p
 - mrxsmb!SmbWskReceiveComplete+0x1d:
 - fffff80a`731d696d 488bda mov rbx,rdx
 - kd> p
 - mrxsmb!SmbWskReceiveComplete+0x20:
 - fffff80a`731d6970 4c8bb2b8000000 mov r14,qword ptr [rdx+0B8h]
 - …………
 - kd> p
 - mrxsmb!SmbWskReceiveComplete+0x7f:
 - fffff80a`731d69cf 4d8b4640 mov r8,qword ptr [r14+40h]//1
 - kd> dd r14+40
 - ffffc10c`a01ba168 9fdf3c58 ffffc10c
 
可以看到,這個(gè)過程并沒有對(duì)這個(gè)值進(jìn)行檢查,由于結(jié)構(gòu)體不透明,不能確定到底對(duì)應(yīng)存放的是什么,但其實(shí)這個(gè)結(jié)構(gòu)體的連續(xù)調(diào)用我們可以理解為KPCR -> KTHREAD -> _EPROCESS -> Token這種關(guān)系,在Windows內(nèi)核有很多這樣的域以及相關(guān)的結(jié)構(gòu)體,而相互又是嵌套的。
這個(gè)結(jié)構(gòu)體的值為0x0的原因可能就是由于這個(gè)complete部分的數(shù)據(jù)包是由于SMB Tree Connect過長(zhǎng)引起的,而mrxsmb20.sys中卻沒有對(duì)相關(guān)結(jié)構(gòu)體進(jìn)行檢查。
- kd> p
 - mrxsmb!VctIndDataReady+0x36:
 - fffff80a`731d6a56 498bf8 mov rdi,r8
 - …………
 - kd> p
 - mrxsmb!VctIndDataReady+0x146:
 - fffff80a`731d6b66 488bd7 mov rdx,rdi
 - kd> p
 - mrxsmb!VctIndDataReady+0x149:
 - fffff80a`731d6b69 488bcb mov rcx,rbx
 - kd> p
 - mrxsmb!VctIndDataReady+0x14c:
 - fffff80a`731d6b6c ff15eeed0200 call qword ptr [mrxsmb!_guard_dispatch_icall_fptr (fffff80a`73205960)]
 - kd> r rdx
 - rdx=ffffc10c9fdf3c58
 - kd> t
 - mrxsmb!guard_dispatch_icall_nop:
 - fffff80a`731d8a30 ffe0 jmp rax
 - kd> p
 - mrxsmb20!Smb2TreeConnect_CopyData:
 - fffff80a`7546b6c0 48895c2410 mov qword ptr [rsp+10h],rbx
 
最后進(jìn)入CopyData后,會(huì)引用這個(gè)結(jié)構(gòu)體+98偏移位置的值,進(jìn)入漏洞觸發(fā)的函數(shù),而沒有對(duì)這個(gè)值進(jìn)行檢查。
- kd> p
 - mrxsmb20!Smb2TreeConnect_CopyData+0x32:
 - fffff80a`7546b6f2 488b8b98000000 mov rcx,qword ptr [rbx+98h]
 - kd> p
 - mrxsmb20!Smb2TreeConnect_CopyData+0x39:
 - fffff80a`7546b6f9 e8c210ffff call mrxsmb20!Smb2ValidateNegotiateInfo (fffff80a`7545c7c0)
 - kd> dd rbx+98
 - ffffc10c`9fdf3cf0 00000000 00000000
 
最后在函數(shù)中引用空指針,引發(fā)了BSOD。























 
 
 
 
 
 
 