关于微软Windows远程内核崩溃漏洞CVE-2018-1040…

2018-06-27 09:49:23来源:红黑联盟 阅读 ()

新老客户大回馈,云服务器低至5折

在2018年1月底,FortiGuard Labs团队在微软Windows中发现了一个远程内核崩溃漏洞,并按照Fortinet公司负责任的披露流程向微软进行了报告。6月12日,微软发布了一份包含此漏洞修复程序的公告,并将其标识为CVE-2018-1040。

这个漏洞存在于微软Windows代码完整性内核模块“ci.dll”中。所有流行的Windows版本都受到影响,包括Windows 10、Windows 7、Windows 8.1、Windows Server 2008、Windows Server 2012和Windows Server 2016。

漏洞可以通过在网站或SMB共享远程下载一个精心制作的.DLL或.LIB文件到Windows上来触发。当使用IE或Edge下载文件并保存时,将执行Windows内核指针解引用到无效地址。因此,会发生Windows Bugcheck(内核崩溃)。在Windows 10上,系统重新启动后,用户登录时会发生内核崩溃。这导致Windows 10内核的崩溃出现无限循环。

在这篇文章中,我将分享关于这个漏洞的详细分析。

分析

要重现此远程内核崩溃漏洞,你可以在Windows 10上打开IE或Edge,输入url http://192.168.0.111/poc.dll(它可以是托管PoC文件的任何URL),然后“在弹出窗口中选择“保存。当保存文件poc.dll时,可以看到Windows 10 Bugcheck(内核崩溃)。对于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文件。在微软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的尺寸大小(这是一个精心制作的大小,正确的大小应该是0x200)。在计算CI.dll中的函数CI!CipImageGetImageHash中的sha1散列块大小时,会导致整数溢出。溢出的块大小是0xfffffeb6。通过调用函数CI!SymCryptSha1AppendBlocks,计算得到溢出块的大小为0xfffe7a。由于制作的sha1块尺寸过大,导致大循环和内核内存读访问冲突。因此,会发生Windows Bugcheck(内核崩溃)。

图2.包含精心制作的SizeOfHeaders的poc.dll

通过你想工程和跟踪,我们可以看到函数_CipImageGetImageHash的调用导致一个sha1块大小整数溢出。

PAGE:85D15618 _CipImageGetImageHash@36 proc near ; CODE XREF:

......

PAGE:85D1571F mov edx, edi

PAGE:85D15721 mov ecx, [ebp+arg_4]

PAGE:85D15724 call _HashpHashBytes@12 ; HashpHashBytes(x,x,x)

PAGE:85D15729 lea edx, [esi+0A0h]

PAGE:85D1572F

PAGE:85D1572F loc_85D1572F: ; CODE XREF: CipImageGetImageHash(x,x,x,x,x,x,x,x,x)+CF↑j

PAGE: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=83560150

PAGE:85D15737 add eax, [ebp+BaseAddress] ----> here [ebp+BaseAddress]=83560000

PAGE:85D1573A push eax ; ---------> So, after the above calculation, eax occurs integer subtraction overflow,result in eax=fffffeb6

PAGE:85D1573B mov ecx, [ebp+arg_4]

PAGE:85D1573E call _HashpHashBytes@12 ------> the function call chain finally results in a kernel crash

PAGE:85D15743 mov esi, [edi+54h] ;

PAGE:85D15746 mov [ebp+var_30], esi

In following function, an insufficient bounds check is performed:

.text:85D0368C @SymCryptHashAppendInternal@16 proc near

.text:85D0368C ; CODE XREF: SymCryptSha1Append(x,x,x)+10↑p

.text:85D0368C ; SymCryptMd5Append(x,x,x)+10↑p

.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)+46↑j

.text:85D03735 ; SymCryptHashAppendInternal(x,x,x,x)+52↑j

.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)+A7↑j

.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块的溢出,它最终调用了以下函数:

.text:85D01060 @SymCryptSha1AppendBlocks@16 proc near ; CODE XREF: SymCryptSha1Result(x,x)+40↑p

......

.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处时,会发生整数溢出。

精心制作的大小值会导致计算错误的sha1块大小(它会变成一个负值)。由于边界检查不足,sha1计算函数进入一个较大的循环,这会导致内存读取访问冲突。最后,发生系统Bugcheck(内核崩溃)。

解决方案

所有易受攻击的微软Windows用户都被鼓励升级到最新的Windows版本或应用最新的补丁。此外,已经部署了Fortinet IPS解决方案的组织已经通过以下签名保护不受此漏洞影响:

MS.Windows.Code.Integrity.Module.DoS

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:虽然黑客删除了数据,但A站数据泄露是否该被追责

下一篇:【安全防护】恶意进程要怎么结束?