Windows Heap Exploitation Win 2 KSP 0 through

  • Slides: 59
Download presentation
Windows Heap Exploitation (Win 2 KSP 0 through Win. XPSP 2) Original Can. Sec.

Windows Heap Exploitation (Win 2 KSP 0 through Win. XPSP 2) Original Can. Sec. West 04 Presentation: Matt Conover & Oded Horovitz XP SP 2 Additions added/presented, Matt Conover @ Sy. Scan 2004

Agenda § § § “Practical” Windows heap internals How to exploit Win 2 K

Agenda § § § “Practical” Windows heap internals How to exploit Win 2 K – Win. XP SP 1 heap overflows 3 rd party (me ) assessment of Win. XP SP 2 improvements How to exploit Win. XP SP 2 heap overflows Summary

Windows Heap Internals Many heaps can coexist in one process (normally 2 -3) PEB

Windows Heap Internals Many heaps can coexist in one process (normally 2 -3) PEB 0 x 0010 Default Heap 0 x 0080 Heaps Count 0 x 0090 Heap List 0 x 70000 Default Heap 0 x 170000 2 nd Heap

Windows Heap Internals Important heap structures Segment List Virtual Allocation list Free Lists Lookaside

Windows Heap Internals Important heap structures Segment List Virtual Allocation list Free Lists Lookaside List

Windows Heap Internals Introduction to Free Lists § § § 128 doubly-linked list of

Windows Heap Internals Introduction to Free Lists § § § 128 doubly-linked list of free chunks (from 8 bytes to 1024 bytes) Chunk size is table row index * 8 bytes Entry [0] is a variable sized free lists contains buffers of 1 KB <= size < 512 KB, sorted in ascending order 0 1400 2000 16 16 48 48 1 2 3 4 5 6 2000 2408

Windows Heap Internals Lookaside Table § Used for “fast” allocates and deallocates when available

Windows Heap Internals Lookaside Table § Used for “fast” allocates and deallocates when available § Starts empty § 128 singly-linked lists of busy chunks (free but left marked as busy) 0 1 2 16 3 4 5 6 48 48

Windows Heap Internals Why have lookasides at all? Speed! § Singly-linked § Used to

Windows Heap Internals Why have lookasides at all? Speed! § Singly-linked § Used to quickly allocate or deallocate § No coalescing (leads to fragmentation) § So the lookaside lists “fill up” quickly (4 entries)

Windows Heap Internals 01 – Busy 02 – Extra present 04 – Fill pattern

Windows Heap Internals 01 – Busy 02 – Extra present 04 – Fill pattern 08 – Virtual Alloc 10 – Last entry 20 – FFU 1 40 – FFU 2 80 – No coalesce Basic chunk structure – 8 Bytes Previous chunk size Self Size 0 1 Overflow direction 2 3 Segment Index 4 5 Unused Tag index bytes (Debug) Flags 6 7 8

Windows Heap Internals Free chunk structure – 16 Bytes Previous chunk size Self Size

Windows Heap Internals Free chunk structure – 16 Bytes Previous chunk size Self Size Segment Index Next chunk 0 1 2 Unused Tag index bytes (Debug) Flags Previous chunk 3 4 5 6 7 8

Windows Heap Internals Allocation algorithm (high level) § § § If size >= 512

Windows Heap Internals Allocation algorithm (high level) § § § If size >= 512 K, virtual memory is used (not on heap) If < 1 K, first check the Lookaside lists. If there is no free entries on the Lookaside, check the matching free list If >= 1 K or no matching entry was found, use the heap cache (not discussed in this presentation). If >= 1 K and no free entry in the heap cache, use Free. Lists[0] (the variable sized free list) If still can’t find any free entry, extend heap as needed

Windows Heap Internals Allocate algorithm – Free. Lists[0] § This is usually what happens

Windows Heap Internals Allocate algorithm – Free. Lists[0] § This is usually what happens for chunk sizes > 1 K § Free. Lists[0] is sorted from smallest to biggest § Check if Free. Lists[0]->Blink to see if it is big enough (the biggest block) § Then return the smallest free entry from free list[0] to fulfill the request, like this: While (Entry->Size < Needed. Size) Entry = Entry->Flink

Windows Heap Internals Allocate algorithm – Virtual Allocate § Used when Chunk. Size >

Windows Heap Internals Allocate algorithm – Virtual Allocate § Used when Chunk. Size > Virtual. Alloc threshold (508 K) § Virtual allocate header is placed on the beginning of the buffer § Buffer is added to busy list of virtually allocated buffers (this is what Halvar’s Virtual. Alloc overwrite is faking)

Windows Heap Internals Free Algorithm (high level) • • If the chunk < 512

Windows Heap Internals Free Algorithm (high level) • • If the chunk < 512 K, it is returned to a lookaside or free list If the chunk < 1 K, put it on the lookaside (can only hold 4 entries) If the chunk < 1 K and the lookaside is full, put it on the free list If the chunk > 1 K put it on heap cache (if present) or Free. Lists[0]

Windows Heap Internals Free Algorithm – Free to Lookaside Free buffer to Lookaside list

Windows Heap Internals Free Algorithm – Free to Lookaside Free buffer to Lookaside list only if: § § § The lookaside is available (e. g. , present and unlocked) Requested size is < 1 K (to fit the table) Lookaside is not “full” yet (no more than 3 entries already) To add an entry to the Lookaside: § § § Put to the head of Lookaside Point to former head of Lookaside Keep the buffer flags set to busy (to prevent coalescing)

Windows Heap Internals Free Algorithm – Coalesce Step 1: Buffer free Step 2: Buffer

Windows Heap Internals Free Algorithm – Coalesce Step 1: Buffer free Step 2: Buffer removed from free list A B C Step 3: Buffer removed from free list A + B Coalesced A C A + B + C Coalesced A Step 4: Buffer placed back on the free list

Windows Heap Internals Free Algorithm – Coalesce Where coalesce cannot happen: § Chunk to

Windows Heap Internals Free Algorithm – Coalesce Where coalesce cannot happen: § Chunk to be freed is virtually allocated § Chunk to be freed will be put on Lookaside § Chunk to be coalesced with is busy § Highest bit in chunk flags is set § …

Windows Heap Internals Free Algorithm – Coalesce (cont) Where coalesce cannot happen: § Chunk

Windows Heap Internals Free Algorithm – Coalesce (cont) Where coalesce cannot happen: § Chunk to be freed is first no backward coalesce § Chunk to be freed is last no forward coalesce § The size of the coalesced chunk would be >= 508 K

Windows Heap Internals Summary – Questions? Just remember: • • Lookasides are allocated from

Windows Heap Internals Summary – Questions? Just remember: • • Lookasides are allocated from and freed to before free lists Free. Lists[0] is mainly used for 1 K <= Chunk. Size < 512 K Coalescing only happens for entries going onto Free. List, not lookaside list Entries on a certain lookaside will stay there until they are allocated from

Heap Exploitation: Basic Terms 4 -byte Overwrite Able to overwrite any arbitrary 32 -bit

Heap Exploitation: Basic Terms 4 -byte Overwrite Able to overwrite any arbitrary 32 -bit address (Where. To) with an arbitrary 32 -bit value (With. What) 4 -to-n-byte Overwrite Using a 4 -byte overwrite to indirectly cause an overwrite of an arbitrary-n bytes

Arbitrary Memory Overwrite Explained Coalesce-On-Free 4 -byte Overwrite § § Utilize coalescing algorithms of

Arbitrary Memory Overwrite Explained Coalesce-On-Free 4 -byte Overwrite § § Utilize coalescing algorithms of the heap This is the method first discussed by Oded and I at CSW 04 – it is our preferred method for reliable heap exploitation on all versions < XPSP 2 Just make sure to fill the Lookaside[Chunk. Size] (put 4 entries on heap) before freeing a chunk of Chunk. Size to ensure coalescing Arbitrary overwrite happens when the overflowed buffer gets freed Index Flags < 64 != 1 Overflow start Fake Flink (With. What) Fake Blink (Where. To)

Arbitrary Memory Overwrite Lookaside List Head Overwrite: 4 -to-n-byte overwrite § What we want

Arbitrary Memory Overwrite Lookaside List Head Overwrite: 4 -to-n-byte overwrite § What we want to do is overwrite a Lookaside list head and then allocate from it § We must be the first one to allocate that size § We will get a chunk back pointing to whatever location in memory we want § Use this to overwrite a function pointer or put the shellcode at a known writable location

Arbitrary Memory Overwrite Lookaside List Head Overwrite: How To • Use the Coalesce-on-Free Overwrite,

Arbitrary Memory Overwrite Lookaside List Head Overwrite: How To • Use the Coalesce-on-Free Overwrite, with these values: • • • To calculate the Fake. Chunk. Blink value: • • Fake. Chunk. Blink = &Lookaside[Chunk. Size] where Chunk. Size is a pretty infrequently allocated size Fake. Chunk. Flink = what we want a pointer to Lookaside. Table = Heap. Base + 0 x 688 Index = (Chunk. Size/8)+1 Fake. Chunk. Blink = Lookaside. Table + Index * Entry. Size (0 x 30) Set Fake. Chunk. Flags = 0 x 20, Fake. Chunk. Index = 1 -63, Fake. Chunk. Previous. Size = 1, Fake. Chunk. Size = 1

Exploition Made Simple Overwrite PEB lock routine to point to PEB space Put shellcode

Exploition Made Simple Overwrite PEB lock routine to point to PEB space Put shellcode into PEB space Then cause the PEB lock routine to execute PEB Header PEB lock/unlock function pointers 0 x 7 ffdf 020, 0 x 7 ffdf 024 0 x 7 ffdf 130 ~1 k of payload

Exploitation Made Simple Win 2 K through Win. XP SP 1 in a single

Exploitation Made Simple Win 2 K through Win. XP SP 1 in a single attempt: § First 4 -byte overwrite: § § § 4 -to-n-byte overwrite: § § § Blink = &Lookaside[(n/8)+1] Flink = 0 x 7 ffdf 154 Be the first to allocate n bytes (cause Heap. Alloc(n)): § § Blink = 0 x 7 ffdf 020, Flink = 0 x 7 ffdf 154 Put your shellcode into the returned buffer All done! Either wait, or cause a crash immediately: § For example, do 4 -byte overwrite with Blink = 0 x. ABAB

Exploitation Made Simple Forcing Shellcode To Run § Most applications (read: everyone but MSSQL)

Exploitation Made Simple Forcing Shellcode To Run § Most applications (read: everyone but MSSQL) don’t specially handle access violations § An access violation results in Exit. Process() being called § Once the process attempts to exit, Exit. Process() is called § The first thing Exit. Process() does is call the PEB lock routine § Thus, causing crash = instant shellcode execution Nice

Exploitation Made Simple Demo

Exploitation Made Simple Demo

Heap Exploitation Questions? This technique we just covered is very reliably, providing success almost

Heap Exploitation Questions? This technique we just covered is very reliably, providing success almost every time on all Win 2 K (all service packs) and Win. XP (up to SP 2) On to XP SP 2….

XP Service Pack 2 Effects on Heap Exploitation § New low fragmentation heap for

XP Service Pack 2 Effects on Heap Exploitation § New low fragmentation heap for chunks >= 16 K § PEB “shuffling” (aka randomization) § New security cookie in each heap chunk § Safe unlinking: (usually) stops 4 -byte overwrites

XP Service Pack 2 PEB Randomization § In theory, it could have a big

XP Service Pack 2 PEB Randomization § In theory, it could have a big impact on heap exploitation – though not in reality § Prior to XP SP 2, it used to always be at the highest page available (0 x 7 ffdf 000) § The first (and ONLY the first) TEB is also randomized § They seem to never be below 0 x 7 ffd 4000

XP Service Pack 2 PEB Randomization – Does it make any difference? Not much,

XP Service Pack 2 PEB Randomization – Does it make any difference? Not much, randomization is definitely a misnomer If 2 threads are present: We can write to 0 x 7 ffdf 000 -0 x 7 ffdffff, and 2 other pages between 0 x 7 ffd 4000 -0 x 7 ffdefff If 3 threads are present: 0 x 7 ffde 000 -0 x 7 ffdffff 2 other pages between 0 x 7 ffd 4000 -0 x 7 ffdefff … If 11 threads are present: 100% success, no empty pages

XP Service Pack 2 PEB Randomization – Summary Provides little protection for… § Any

XP Service Pack 2 PEB Randomization – Summary Provides little protection for… § Any application that have m workers per n connections (IIS? Exchange? ) § Any service in dllhost/services/svchost or any other “active” surrogate process

XP Service Pack 2 Heap header cookie *reminder: overflow direction XP SP 2 Header

XP Service Pack 2 Heap header cookie *reminder: overflow direction XP SP 2 Header Self Size Previous chunk size New Cookie Flags Unused bytes Current Header Self Size Previous chunk size Segment Index Flags Unused Tag index bytes (Debug) 0 1 2 3 4 5 6 Segment Index 7 8

XP Service Pack 2 Heap header cookie calculation § If ((Address. Of. Chunk. Header

XP Service Pack 2 Heap header cookie calculation § If ((Address. Of. Chunk. Header / 8) XOR Chunk>Cookie XOR Heap->Cookie != 0) CORRUPT § Since the cookie has only 8 -bits, it has 2^8 = 256 possible keys § We’ll randomly guess the security cookie, on average, 1 of every 256 attempts

XP Service Pack 2 § On the normal Win. XP SP 2 system, corrupting

XP Service Pack 2 § On the normal Win. XP SP 2 system, corrupting a chunk will do nothing § Since we only overwrite the Flink/Blink of the chunk, we corrupt no other chunks § Thus we can keep trying until we run out of memory

XP Service Pack 2 Summary so far… At this point, we see that we

XP Service Pack 2 Summary so far… At this point, we see that we can with enough time trivially defeat all the other protection mechanisms. On to “safe” unlinking…

XP Service Pack 2 Safe Unlinking § Safe unlinking means that Remove. List. Entry(B)

XP Service Pack 2 Safe Unlinking § Safe unlinking means that Remove. List. Entry(B) will make this check: (B->Flink)->Blink == B && (B->Blink)->Flink == B In other words: C->Blink == B && A->Flink == B Can it be evaded? Yes, in one particular case. Header to free A B C

XP Service Pack 2 Un. Safe-Unlinking Free. List Overwrite Technique p = Heap. Alloc(n);

XP Service Pack 2 Un. Safe-Unlinking Free. List Overwrite Technique p = Heap. Alloc(n); Fill. Lookaside(n); Heap. Free(p); Empty. Lookaside(n); Overwrite p[0] (somewhere on the heap) with: p->Flags = Busy (to prevent accidental coalescing) p ->Flink = (BYTE *)&List. Head[(n/8)+1] - 4 p ->Blink = (BYTE *)&List. Head[(n/8)+1] + 4 Heap. Alloc(n); // defeats safe unlinking (ignore result) p = Heap. Alloc(n); // defeats safe unlinking // p now points to &List. Head[(n/8)]. Blink

XP Service Pack 2 Defeating Safe Unlinking (before overwrite) List. Head[n-1] List. Head[n+1] [4]

XP Service Pack 2 Defeating Safe Unlinking (before overwrite) List. Head[n-1] List. Head[n+1] [4] Blink [0] Flink Free. Chunk

XP Service Pack 2 Defeating Safe Unlinking: Step 1 (Overwrite) List. Head[n-1] List. Head[n+1]

XP Service Pack 2 Defeating Safe Unlinking: Step 1 (Overwrite) List. Head[n-1] List. Head[n+1] [4] Blink [0] Flink [4] Blink Free. Chunk [0] Flink Now call Heap. Alloc(n) to unlink Free. Chunk from List. Head Free. Chunk->Blink->Flink == *(*(Free. Chunk+4)+0) Free. Chunk->Flink->Blink) == *(*(Free. Chunk+0)+4) Both point to Free. Chunk, unlink proceeds!

XP Service Pack 2 Defeating Safe Unlinking: Step 2 (1 st alloc) List. Head[n-1]

XP Service Pack 2 Defeating Safe Unlinking: Step 2 (1 st alloc) List. Head[n-1] [4] Blink [0] Flink List. Head[n] List. Head[n+1] [4] Blink [0] Flink Free. Chunk->Blink->Flink = Free. Chunk->Flink->Blink = Free. Chunk->Blink Returns pointer to previous Free. Chunk

XP Service Pack 2 Defeating Safe Unlinking: Step 3 (2 nd alloc) List. Head[n-1]

XP Service Pack 2 Defeating Safe Unlinking: Step 3 (2 nd alloc) List. Head[n-1] [4] Blink [0] Flink List. Head[n] List. Head[n+1] [4] Blink [0] Flink Returns pointer to &List. Head[n-1]. Blink Now the Free. Lists point to whatever data the user puts in it

XP Service Pack 2 Questions?

XP Service Pack 2 Questions?

XP Service Pack 2 Unsafe-Unlinking Free. List Overwrite Technique § For vulnerabilities where you

XP Service Pack 2 Unsafe-Unlinking Free. List Overwrite Technique § For vulnerabilities where you can control the allocation size, safe unlinking can be evadable. § But is this reliable? Hardly. § …

XP Service Pack 2 Unsafe-Unlinking Free. List Overwrite Technique (cont) § We have to

XP Service Pack 2 Unsafe-Unlinking Free. List Overwrite Technique (cont) § We have to flood the heap with this repeating 8 byte sequence: [Free. List. Head-4][Free. List. Head+4] And hope the Chunk’s Flink/Blink pair is within the range we can overflow § But there is an even easier method…

XP Service Pack 2 Chunk-on-Lookaside Overwrite Technique § In fact on XP SP 2,

XP Service Pack 2 Chunk-on-Lookaside Overwrite Technique § In fact on XP SP 2, there is an even easier method § Lookasides lists take precedence over free lists § This is quite convenient because… § Lookaside lists (singly linked) are easier to exploit than the free lists (doubly linked)

XP Service Pack 2 Chunk-on-Lookaside Overwrites § Heap. Alloc checks the lookaside before the

XP Service Pack 2 Chunk-on-Lookaside Overwrites § Heap. Alloc checks the lookaside before the free list § There is no check to see if the cookie was overwritten since it was freed § It is a singly-linked list, thus the safe unlinking check doesn’t apply § Result: a clean exploitation technique (albeit with brute-forcing required)

XP Service Pack 2 Chunk-on-Lookaside Overwrites (Technique Summary) // We need at least 2

XP Service Pack 2 Chunk-on-Lookaside Overwrites (Technique Summary) // We need at least 2 entries on lookaside a_n[0] = Heap. Alloc(n) a_n[1] = Heap. Alloc(n) Heap. Free(a_n[1]) Heap. Free(a_n[0]) Overwrite a_n[0] (somewhere on the heap) with: a_n[0]. Flags = Busy (to prevent accidental coalescing) a_n[0]. Flink = Address. We. Want Heap. Alloc(n) // discard, this returns a_n[0] p = Heap. Alloc(n) p now points to Address. We. Want

XP Service Pack 2 Chunk-on-Lookaside Overwrite - Success rate? § Reqiures overwriting a chunk

XP Service Pack 2 Chunk-on-Lookaside Overwrite - Success rate? § Reqiures overwriting a chunk already freed to the lookaside § If an attacker overflows a buffer repeatedly, how often will he/she need to before succeeding?

XP Service Pack 2 Chunk-on-Lookaside Overwrite – Empirical results § § § § 64

XP Service Pack 2 Chunk-on-Lookaside Overwrite – Empirical results § § § § 64 K heap with 1 segment All chunk sizes between 8 -1024 bytes Max overflow size = 1016 bytes Random number of allocs between 10 -1000 Free probability of 50% Took an average of 84 allocations to be within overflow range It will take at least 2 overwrites (one to overwrite a function pointer, one to place shellcode)

XP Service Pack 2 Chunk-on-Lookaside Overwrite – Empirical results § Application specific function pointer

XP Service Pack 2 Chunk-on-Lookaside Overwrite – Empirical results § Application specific function pointer and writable location for shellcode: § § 84*2 = 168 attempts to execute shellcode Using PEB lock routine + PEB space (application generic): § § 84*2*12=2, 016 attempts to execute shellcode The 12 is for the 12 possible locations of the PEB due to PEB randomization

XP Service Pack 2 Chunk-on-Lookaside Overwrite – Summary § To exploit a non-application specific

XP Service Pack 2 Chunk-on-Lookaside Overwrite – Summary § To exploit a non-application specific heap exploit will take 2000+ attempts to do it reliably § But now ask yourself… how long does it take generate 2000 heap overwrite attempts? § Lets be overly conservative and assume 5 minutes § That will really slow down a worm… § But will it help you if someone is specifically trying to hack your machine?

XP Service Pack 2 Low Fragmentation Heap (LFH) • Looks really solid… kudos to

XP Service Pack 2 Low Fragmentation Heap (LFH) • Looks really solid… kudos to its author • Uses 32 -bit cookie • Obscures address of Lookaside list heads: • Chunk. Sizes = *((DWORD *)Chunk) // (Chunk. Size<<16|Prev. Chunk. Size) p. Lookaside. Entry = (DWORD)Chunk / 8 p. Lookaside. Entry ^= Lookaside->Key p. Lookaside. Entry ^= Chunk. Sizes p. Lookaside. Entry ^= Rtlp. LFHKey …

XP Service Pack 2 Low Fragmentation Heap (LFH) • The Rtlp. LFHKey is a

XP Service Pack 2 Low Fragmentation Heap (LFH) • The Rtlp. LFHKey is a “show stopper”: push call mov lea push call imul push mov • … eax _Rtl. Random. Ex@4 _Rtlp. LFHKey, eax, [ebp+var_4] eax _Rtl. Random. Ex@4 eax, _Rtlp. LFHKey esi _Rtlp. LFHKey, eax

XP Service Pack 2 Low Fragmentation Heap (LFH) • Must be enabled manually (via

XP Service Pack 2 Low Fragmentation Heap (LFH) • Must be enabled manually (via NTDLL!Rtl. Set. Heap. Information or KERNEL 32!Heap. Set. Information) • It is used for chunks < 16 K • It is not used by anything on XP SP 2 Professional • What irony

Summary Win 2 K – Win. XP SP 1 § Fixed heap base and

Summary Win 2 K – Win. XP SP 1 § Fixed heap base and fixed PEB allow for writing very stable exploits § Overwriting Free. List/Lookaside list heads gives us the ability to overwrite any writable address with 1 K of data

Summary Win. XP SP 2 § Decreases reliability (more bruteforcing is necessary) § But

Summary Win. XP SP 2 § Decreases reliability (more bruteforcing is necessary) § But with enough time, exploitation will still succeed § XP SP 2 will really slow worm propagation, but not help a targeted victim §. . .

Summary Win. XP SP 2 § Heap corruption handling is weak § PEB randomization

Summary Win. XP SP 2 § Heap corruption handling is weak § PEB randomization is weak § Safe unlinking is evadable § Non-LFH cookie checks are weak § LFH looks good

Summary Solutions § Use low fragmentation heap by default § § Expand PEB randomization

Summary Solutions § Use low fragmentation heap by default § § Expand PEB randomization over 1 MB or so § § Most machines have 1 GB+ RAM these days Inform user if heap corruption exceeds a threshold § § Just be sure it is the lowest address on the heap If I have an application with 50 corrupt chunks in 60 seconds, I want to know someone is owning me Check security cookies on allocation also

Summary The eventual death of 4 byte overwrites… § Whether an attacker can predict

Summary The eventual death of 4 byte overwrites… § Whether an attacker can predict the Chunk. Size/Prev. Size or not, he/she won’t be able to predict a larger security cookie (like LFH has). § Heap exploits will focus more on attacking application data on the heap (not the heap itself)