當前位置:
首頁 > 新聞 > Microsoft Windows CVE-2018-1040漏洞分析

Microsoft Windows CVE-2018-1040漏洞分析

2018年1月底,FortiGuard Labs team在Microsoft Windows中發現了一個遠程內核崩潰漏洞,並遵循Fortinet公司的披露流程向微軟報告。6月12日,微軟發布了一個諮詢通告,其中包含針對此漏洞的修復程序,並將其標識為CVE-2018-1040。

此內核崩潰漏洞位於Microsoft Windows代碼完整性內核模塊「ci.dll」中。所有主流的Windows版本都受到影響,包括Windows 10,Windows 7,Windows 8.1,Windows Server 2008,Windows Server 2012和Windows Server 2016。

我發現的這個漏洞可以通過從網站或SMB共享上遠程下載構造的.dll或.lib文件來觸發。使用IE或Edge下載文件並保存時,會導致Windows內核指針間接引用無效地址。因此,引發Windows錯誤檢查(內核崩潰)。在Windows 10上,系統重新啟動後,用戶登錄時會發生內核崩潰。這會導致Windows 10內核一直陷入循環的崩潰之中。

在本博客中,我想分享一下我對這個漏洞的詳細分析。

分析

要重現此遠程內核崩潰漏洞,可以在Windows 10上打開IE或Edge,輸入url http://192.168.0.111/poc.dll(它可以是任何託管PoC文件的URL),然後在彈出窗口中選擇「保存「。當保存文件poc.dll時,可以看到Windows 10錯誤檢查(內核崩潰)。對於Windows 10中的內核崩潰,即使重新啟動也會繼續發生,這會導致Windows 10無法正常工作。對於用戶,可能需要重新安裝系統。

下面是發生崩潰時的堆棧調用。

圖1.發生崩潰時的堆棧調用

從上面的調用堆棧輸出中,我們可以看到在調用函數「KERNELBASE!GetFileVersionInfoSizeExW」時會發生內核崩潰,之後它會調用函數「KERNELBASE!LoadLibraryExW」。最後,它會導致整個內核崩潰。

當IE / Edge下載.dll或.lib文件並保存在磁碟上時,它將調用函數「KERNELBASE!GetFileVersionInfoSizeExW」來檢索.dll / .lib版本信息。要獲取.dll / .lib版本信息,它會調用函數「KERNELBASE!LoadLibraryExW」以載入dwFlags等於0x22的.dll / .lib文件。在Microsoft MSDN中搜索,我們可以看到dwFlags 0x22是「LOAD_LIBRARY_AS_DATAFILE(0x00000002)」和「LOAD_LIBRARY_AS_IMAGE_RESOURCE(0x00000020)」的組合。因此,IE / Edge會將下載的.dll / .lib文件載入為資源.dll / .lib和數據文件來獲取相關信息。構造的poc.dll會引發Windows 10發生內核崩潰,即使重新啟動也無法恢復系統。這是因為用戶登錄Windows時,會掃描IE / Edge臨時目錄中的.dll / .lib文件。

函數LoadLibraryExW載入構造的PoC文件poc.dll。當它處理SizeOfHeaders時,它會得到一個0x06的值(正確的size 是0x200)。在計算CI.dll中的函數CI!CipImageGetImageHash中的sha1散列塊size時,會導致整數溢出。溢出的塊size是0xfffffeb6。計算後獲取的溢出塊size為0xfffffe7a,由於構造的sha1塊size過大,調用函數CI!SymCryptSha1AppendBlocks會導致大循環和內核內存讀取訪問衝突。因此,會發生Windows錯誤檢查(內核崩潰)。

圖2.包含精心製作的SizeOfHeaders的poc.dll

通過逆向和跟蹤,可以看到函數_CipImageGetImageHash的調用導致sha1塊size整數溢出。

PAGE:85D15618 _CipImageGetImageHash@36 proc near ; CODE XREF:......PAGE:85D1571F mov edx, ediPAGE:85D15721 mov ecx, [ebp+arg_4]PAGE:85D15724 call _HashpHashBytes@12 ; HashpHashBytes(x,x,x)PAGE:85D15729 lea edx, [esi+0A0h]PAGE:85D1572FPAGE:85D1572F loc_85D1572F: ; CODE XREF: CipImageGetImageHash(x,x,x,x,x,x,x,x,x)+CFjPAGE:85D1572F mov edi, [ebp+arg_10]PAGE:85D15732 mov eax, [edi+54h] ; -----> here [edi+54h] is obtained from poc.dll at offset 0x104, its value is 0x06.PAGE:85D15735 sub eax, edx ; -----> here edx=83560150PAGE:85D15737 add eax, [ebp+BaseAddress] ----> here [ebp+BaseAddress]=83560000PAGE:85D1573A push eax ; ---------> So, after the above calculation, eax occurs integer subtraction overflow, result in eax=fffffeb6PAGE:85D1573B mov ecx, [ebp+arg_4]PAGE:85D1573E call _HashpHashBytes@12 ------> the function call chain finally results in a kernel crashPAGE:85D15743 mov esi, [edi+54h] ;PAGE:85D15746 mov [ebp+var_30], esiIn following function, an insufficient bounds check is performed:.text:85D0368C @SymCryptHashAppendInternal@16 proc near.text:85D0368C ; CODE XREF: SymCryptSha1Append(x,x,x)+10p.text:85D0368C ; SymCryptMd5Append(x,x,x)+10p.text:85D0368C.text:85D0368C var_18 = dword ptr -18h.text:85D0368C var_14 = dword ptr -14h.text:85D0368C var_10 = dword ptr -10h.text:85D0368C var_C = dword ptr -0Ch.text:85D0368C var_8 = dword ptr -8.text:85D0368C var_4 = dword ptr -4.text:85D0368C Src = dword ptr 8.text:85D0368C MaxCount = dword ptr 0Ch.text:85D0368C.text:85D0368C mov edi, edi.text:85D0368E push ebp .text:85D0368F mov ebp, esp .......85D0372D mov ecx, [ebp+var_8].text:85D03730 mov edx, [ebp+var_18].text:85D03733 jmp short loc_85D0373B.text:85D03735 ; ---------------------------------------------------------------------------.text:85D03735.text:85D03735 loc_85D03735: ; CODE XREF: SymCryptHashAppendInternal(x,x,x,x)+46j.text:85D03735 ; SymCryptHashAppendInternal(x,x,x,x)+52j.text:85D03735 mov ecx, [ebp+Src].text:85D03738 mov [ebp+var_8], ecx.text:85D0373B.text:85D0373B loc_85D0373B: ; CODE XREF: SymCryptHashAppendInternal(x,x,x,x)+A7j.text:85D0373B cmp esi, [edx+18h] ; ----> here [edx+18h] equals 40h, esi equals fffffe7a, due to unsigned integer comparison, the crafted block size is not found.text:85D0373E jb short loc_85D03769.text:85D03740 mov edi, [edx+1Ch].text:85D03743 lea eax, [ebp+var_C].text:85D03746 push eax.text:85D03747 push esi.text:85D03748 mov esi, [edx+0Ch].text:85D0374B add edi, ebx.text:85D0374D mov ecx, esi.text:85D0374F call ds:___guard_check_icall_fptr ; _guard_check_icall_nop(x).text:85D03755 mov edx, [ebp+var_8].text:85D03758 mov ecx, edi.text:85D0375A call esi

隨著sha1塊size的增加,它最終調用以下函數:

.text:85D01060 @SymCryptSha1AppendBlocks@16 proc near ; CODE XREF: SymCryptSha1Result(x,x)+40p.......text:85D010A4 mov eax, [ebp+arg_0] -----> here eax gets the overflowed sha1 block size= 0xfffffe7a.text:85D010A7 mov [esp+0D0h+var_B4], edi.text:85D010AB mov [esp+0D0h+var_C4], ecx.text:85D010AF cmp eax, 40h.text:85D010B2 jb loc_85D02507.text:85D010B8 mov [esp+0D0h+var_58], ecx.text:85D010BC mov ecx, [esp+0D0h+var_C0].text:85D010C0 mov [esp+0D0h+var_54], ecx.text:85D010C4 lea ecx, [edx+8] ;.text:85D010C7 shr eax, 6 -------> the overflowed block size is used as the following loop function counter.text:85D010CA mov [esp+0D0h+var_60], esi.text:85D010CE mov [esp+0D0h+var_5C], edi.text:85D010D2 mov [esp+0D0h+var_68], ecx ;.text:85D010D6 mov [esp+0D0h+var_50], eax -----> here is the loop counter.......text:85D01359 ror edx, 2.text:85D0135C mov ecx, [ecx+28h].text:85D0135F bswap ecx.text:85D01361 mov [esp+0D0h+var_6C], ecx.text:85D01365 mov ecx, eax.text:85D01367 rol ecx, 5.text:85D0136A mov eax, edi.text:85D0136C add ecx, [esp+0D0h+var_6C].text:85D01370 xor eax, edx.text:85D01372 and eax, [esp+0D0h+var_C0].text:85D01376 xor eax, edi.text:85D01378 add edi, 5A827999h.text:85D0137E add eax, ecx.text:85D01380 mov ecx, [esp+0D0h+var_68].text:85D01384 add eax, esi.text:85D01386 mov esi, [esp+0D0h+var_C0].text:85D0138A mov [esp+0D0h+var_84], eax.text:85D0138E ror esi, 2.text:85D01391 mov ecx, [ecx+2Ch] ----> after a large loop call, here it results in a read access violation, so the bugcheck (kernel crash) occurs .text:85D01394 bswap ecx.text:85D01396 mov [esp+0D0h+var_9C], ecx........text:85D024DD mov ecx, [esp+0D0h+var_68].text:85D024E1 mov [esp+0D0h+var_54], eax.text:85D024E5 add ecx, 40h ----> memory access pointer increases 0x40 in each loop.text:85D024E8 mov [esp+0D0h+var_C0], eax.text:85D024EC mov eax, [ebp+arg_0].text:85D024EF sub eax, 40h.text:85D024F2 mov [esp+0D0h+var_68], ecx.text:85D024F6 sub [esp+0D0h+var_50], 1 ------> here the loop counter decreases by 1, not equaling 0, to continue the loop. Due to the overflowed large sha1 block size, here a large loop is executed..text:85D024FE mov [ebp+arg_0], eax.text:85D02501 jnz loc_85D010DD.text:85D02507

從上面的分析中,可以看到,遠程內核崩潰的根本原因是LoadLibraryEx函數無法正確解析作為資源和數據文件構造的.dll / .lib文件。poc.dll包含構造的SizeOfHeaders值為0x06(正確的值應為0x200),該值位於PoC文件中的偏移量0x104處時,發生整數溢出。

構造的size值會導致計算出錯誤的sha1塊size(它會成為負值)。由於邊界檢查不足,sha1計算函數進入一個較大的循環,這會導致內存讀取訪問衝突。最後,發生系統錯誤檢查(內核崩潰)。

解決方案

鼓勵所有存在漏洞的Microsoft Windows用戶升級到最新的Windows版本或應用最新的補丁程序。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

Mcafee區塊鏈威脅報告
Malwarebytes Labs對SamSam勒索軟體的分析

TAG:嘶吼RoarTalk |