SLIDE 1 風水
Heap Feng Shui in JavaScript
Alexander Sotirov
asotirov@determina.com
Black Hat Europe 2007
SLIDE 2 Introduction
○ the ancient art of arranging heap blocks in
- rder to redirect the program control flow to
the shellcode
- Heap Feng Shui in JavaScript
○ precise application data overwrites ○ reliable browser exploitation
SLIDE 3 Overview
- State of the art in browser exploitation
- Internet Explorer heap internals
- HeapLib JavaScript library
- Heap manipulation
- Mitigation
SLIDE 4
Part I State of the art in browser exploitation
SLIDE 5
Stack overflows
Very hard to exploit in most cases:
Target Protection return address stack cookies (/ GS flag) SEH frame SafeSEH exception handler table local variables local variable reordering in the Visual C+ + compiler
SLIDE 6 Heap overflows
Generic heap exploitation is also difficult:
Target Protection doubly-linked list
safe unlinking heap chunk header 8-bit header cookie in XP, XOR of the header data in Vista lookaside linked list removed in Vista
SLIDE 7 What's left?
- Non-array stack overflows
○ very rare
- Use of uninitialized variables
○ stack variables ○ use after free
- Application data on the heap
○ application specific memory allocators ○ function pointers ○ C+ + object pointers
SLIDE 8 WebView setSlice exploit
- Uses heap spraying to fill the browser
heap with shellcode
- Overwrites application data in the
previous heap chunk
- Multiple attempts until it either hits an
- bject pointer, or crashes
SLIDE 9 Heap spraying
Developed by Blazde and SkyLined, used by most browser exploits since 2004.
var x = new Ar r ay( ) ; / / Fi l l 200M B of m em
- r y wi t h copi es of t he
/ / NO P sl i de and shel l code f or ( var i = 0; i < 200; i ++) { x[ i ] = nop + shel l code; }
SLIDE 10 Normal heap layout
used memory: free memory:
0 MB 100 MB 200 MB 300 MB
SLIDE 11 After heap spraying
used memory: free memory: shellcode:
shellcode 0 MB 100 MB 200 MB 300 MB
Address 0x0C0C0C0C is very likely to contain shellcode.
SLIDE 12 Function pointer overwrite
1.
Spray the heap with 200MB of shellcode
2.
Overwrite a function pointer with 0x0C0C0C0C
3.
Call the function pointer
Shellcode at 0x0C0C0C0C nop slide shellcode Function pointer 0x0C0C0C0C
SLIDE 13 Object pointer overwrite
1.
Spray the heap with 200MB of shellcode, using byte 0xC as a nop slide
2.
Overwrite an object pointer with 0x0C0C0C0C
3.
Call a virtual function of the object
Fake object at 0x0C0C0C0C vtable pointer Fake vtable at 0x0C0C0C0C virtual func + 0 virtual func + 4 Shellcode at 0x0C0C0C0C nop slide shellcode
SLIDE 14 Unreliable exploitation
- Heap spraying is a great technique, but
the setSlice exploit is still not reliable
- Overwriting application data requires a
specific layout of heap chunks
- We need to control the heap state
SLIDE 15
Part II Heap Feng Shui
SLIDE 16 Heap Feng Shui
- The heap allocator is deterministic
- Specific sequences of allocations and
frees can be used to control the layout
used: free:
SLIDE 17 Heap Feng Shui
- The heap allocator is deterministic
- Specific sequences of allocations and
frees can be used to control the layout
used: free:
We allocate two 4KB blocks
SLIDE 18 Heap Feng Shui
- The heap allocator is deterministic
- Specific sequences of allocations and
frees can be used to control the layout
We free the first 4KB block used: free:
SLIDE 19 Heap Feng Shui
- The heap allocator is deterministic
- Specific sequences of allocations and
frees can be used to control the layout
The application allocates a 4KB block and reuses our data used: free:
SLIDE 20 Heap Feng Shui
- The heap allocator is deterministic
- Specific sequences of allocations and
frees can be used to control the layout
We just exploited an uninitialized data vulnerability used: free:
SLIDE 21 Heap Feng Shui in JavaScript
- We want to set the heap state before
triggering a vulnerability
- Heap spraying proves that JavaScript can
access the system heap
- We need a way to allocate and free
blocks of an arbitrary size
SLIDE 22
Part III Internet Explorer heap internals
SLIDE 23 Internet Explorer heap usage
Default process heap JavaScript heap Dedicated heaps JavaScript runtime MSHTML engine ActiveX
strings
Dedicated heaps Dedicated heaps
SLIDE 24 JavaScript strings
string size string data null terminator 4 bytes length / 2 bytes 2 bytes
08 00 00 00 41 00 41 00 41 00 41 00 00 00
The string "AAAA" is stored as: We can calculate its size in bytes with:
byt es = l en * 2 + 6 l en = ( byt es - 6) / 2
SLIDE 25
String allocation
var st r 1 = " AAAAAAAAAA" ; / / no al l ocat i on / / al l ocat es a 10 char act er st r i ng var st r 2 = st r 1. subst r ( 0, 10) ; / / al l ocat es a 20 char act er st r i ng var st r 3 = st r 1 + st r 2;
SLIDE 26 String garbage collection
- Mark-and-sweep algorithm, frees all
unreferenced objects
- Triggered by a number of heuristics
- Explicitly by the Col l ect G
ar bage( ) call in Internet Explorer
SLIDE 27 JavaScript alloc and free
var paddi ng = " AAAAAAAAAAAAAAAAAAAAAAAAAAAA… " var st r ; f unct i on al l oc( byt es) { st r = paddi ng. subst r ( 0, ( byt es- 6) / 2) ; } f unct i on f r ee( ) { st r = nul l ; Col l ect G ar bage( ) ; } al l oc( 0x10000) ; / / al l ocat e 64KB m em
f r ee( ) ; / / f r ee m em
SLIDE 28 OLEAUT32 allocator
Not all string allocations and frees reach the system memory allocator
- custom memory allocator in OLEAUT32
- caching of free memory blocks
- 4 bins for blocks of different sizes
- up to 6 free blocks stored in each bin
SLIDE 29
OLEAUT32 alloc function
bi n = t he r i ght bi n f or t he r equest ed si ze i f ( bi n not em pt y) f i nd a bl ock i n t he bi n > r equest ed si ze i f ( f ound) r et ur n bl ock el se r et ur n sysal l oc( si ze) el se r et ur n sysal l oc( si ze)
SLIDE 30
OLEAUT32 free function
bi n = t he r i ght bi n f or t he bl ock si ze i f ( bi n not f ul l ) add bl ock t o bi n el se f i nd t he sm al l est bl ock i n t he bi n i f ( sm al l est bl ock < new bl ock) sysf r ee( sm al l est bl ock) add new bl ock t o bi n el se sysf r ee( new bl ock)
SLIDE 31 Bypassing the cache
- Our freed blocks will go into the cache
- Freeing 6 maximum sized blocks for each
bin will push all smaller blocks out
- Allocating the 6 blocks again will leave
the cache empty
- When the cache is empty, allocations will
come from the system heap
SLIDE 32 Plunger Technique
- 1. Allocate 6 maximum size blocks
- 2. Allocate our blocks
- 3. Free our blocks
- 4. Free 6 maximum size blocks
- 5. Allocate 6 maximum size blocks
OLEAUT32 cache empty maximum size blocks
►
SLIDE 33 Plunger Technique
- 1. Allocate 6 maximum size blocks
- 2. Allocate our blocks
- 3. Free our blocks
- 4. Free 6 maximum size blocks
- 5. Allocate 6 maximum size blocks
OLEAUT32 cache empty maximum size blocks
►
SLIDE 34 Plunger Technique
- 1. Allocate 6 maximum size blocks
- 2. Allocate our blocks
- 3. Free our blocks
- 4. Free 6 maximum size blocks
- 5. Allocate 6 maximum size blocks
OLEAUT32 cache maximum size blocks
►
SLIDE 35 Plunger Technique
- 1. Allocate 6 maximum size blocks
- 2. Allocate our blocks
- 3. Free our blocks
- 4. Free 6 maximum size blocks
- 5. Allocate 6 maximum size blocks
OLEAUT32 cache maximum size blocks free blocks
►
SLIDE 36 Plunger Technique
- 1. Allocate 6 maximum size blocks
- 2. Allocate our blocks
- 3. Free our blocks
- 4. Free 6 maximum size blocks
- 5. Allocate 6 maximum size blocks
OLEAUT32 cache empty maximum size blocks free blocks
►
SLIDE 37
Part IV HeapLib - JavaScript heap manipulation library
SLIDE 38 Introducing HeapLib
- Supports Internet Explorer 5-7
- Object oriented API
- Functions for:
○ heap logging and debugging ○ allocation and freeing of blocks with
arbitrary size and contents
○ high-level heap manipulation function (not
yet supported on Vista)
SLIDE 39 Hello world!
<scr i pt sr c=" heapLi b. j s" ></ scr i pt > <scr i pt > var heap = new heapLi b. i e( ) ;
- heap. gc( ) ;
- heap. debugHeap( t r ue) ;
- heap. al l oc( 512) ;
- heap. al l oc( " BBBBB" , " f oo" ) ;
- heap. f r ee( " f oo" ) ;
- heap. debugHeap( f al se) ;
</ scr i pt >
SLIDE 40
HeapLib Demo
SLIDE 41
Part V Windows Heap Manipulation
SLIDE 42 Windows Heap Overview
Pre-Vista
Heap FreeList[ 0] FreeList[ 1] … FreeList[ 127] Lookaside Lookaside Table Lookaside[ 0] Lookaside[ 1] … Lookaside[ 126]
8 8 1016 1024 2080 8192 8 1016 1016
SLIDE 43
Free Algorithm
i f si ze >= 512KB f r ee wi t h Vi r t ual Fr ee r et ur n i f si ze < 1KB and l ookasi de not f ul l add t o l ookasi de l i st r et ur n coal esce bl ock wi t h f r ee bl ocks ar ound i t i f si ze < 1KB add t o Fr eeLi st [ si ze/ 8] el se add t o Fr eeLi st [ 0]
SLIDE 44 Allocate Algorithm
i f si ze >= 512KB al l oc wi t h Vi r t ual Al l oc r et ur n i f si ze < 1KB i f l ookasi de not em pt y r et ur n a bl ock f r om t he l ookasi de i f Fr eeLi st [ si ze/ 8] not em pt y r et ur n a bl ock f r om Fr eeLi st [ si ze/ 8] i f Fr eeLi st [ 0] not em pt y r et ur n a bl ock f r om Fr eeLi st [ 0] al l ocat e m
em
- r y wi t h Vi r t ual Al l oc
SLIDE 45 Defragmenting the heap
To allocate two consecutive blocks, we need to defragment the heap.
f or ( var i = 0; i < 1000; i ++)
used: free:
SLIDE 46 Defragmenting the heap
To allocate two consecutive blocks, we need to defragment the heap.
f or ( var i = 0; i < 1000; i ++)
used: free:
SLIDE 47 Putting a block on the FreeList
To put a block on the free list, we need to ensure that it is not coalesced.
- heap. al l oc( 0x2010, " f oo" ) ;
- heap. al l oc( 0x2010) ;
- heap. al l oc( 0x2010, " f oo" ) ;
- heap. f r ee( " f oo" ) ;
used: free:
SLIDE 48 Putting a block on the FreeList
To put a block on the free list, we need to ensure that it is not coalesced.
- heap. al l oc( 0x2010, " f oo" ) ;
- heap. al l oc( 0x2010) ;
- heap. al l oc( 0x2010, " f oo" ) ;
- heap. f r ee( " f oo" ) ;
used: free:
SLIDE 49 Emptying the lookaside
To empty the lookaside, allocate enough blocks of the same size.
f or ( var i = 0; i < 100; i ++)
SLIDE 50 Freeing to the lookaside
To put a block on the lookaside, empty it and free the block.
f or ( var i = 0; i < 100; i ++)
- heap. al l oc( 512) ;
- heap. al l oc( 512, " f oo" ) ;
- heap. f r ee( " f oo" ) ;
SLIDE 51
Object pointer overwrite
The lookaside linked list can be used to exploit object pointer overwrites without heap spraying.
1.
Empty the lookaside
2.
Build a fake vtable block
3.
Free the fake vtable to the lookaside
4.
Overwrite an object pointer with the address of the lookaside head
5.
Call a virtual function of the object
SLIDE 52 Object pointer overwrite
m
[ eax] ; get t he vt abl e addr ess push eax ; push t he ' t hi s' poi nt er cal l dwor d pt r [ ecx+08h] ; cal l vi r t ual f unc
Lookaside head (fake object) vtable pointer Free block (fake vtable) NULL jmp short + 4 virtual func + 8 shellcode jmp ecx
NULL disassembles as two sub [ eax] , al instructions
SLIDE 53
Exploit Demo
SLIDE 54 Mitigation
- Heap isolation
- Non-determinism in the heap allocator
SLIDE 55
Questions?
asotirov@determina.com