HEAPS ABOUT HEAPS
This Talk Covers
Windows 2003
: Windows 2003 SP2
: Still most widely used windows server OS
: Still not a lot of heap exploits released
: Still not a lot of heap research released
: Vista -> Ben Hawkes BHUS08
Heap Explotation
: How the heap works
: Freelists vs Lookaside
: Exploitation Techniques
Heap Exploit Walkthrough
: From start to finish
Windows Heap
Multiple Heaps
: Process has default heap
: Can create separate heaps for different uses
: Some loaded .dll create their own heap
: Some .dlls hold pointer to the heap they use
State Of The Heap
: Server restart
: Service restart
: First request
: Long time live, multiple previous requests
Things That Matter
: Everything, IP address, server name, day of
the week
Heap Exploit Difficulties
Safe Unlinking
: On unlink, coalesce, relink from freelist
: Causes the link/unlink to fail if addresses
readable
: Raises a handled exception, execution
proceeds
: Chunk address still returned to caller
Cookie Check
: Cookie checked on free
: Invalid cookie prevents relinking of chunk
HeapSetInformation()
: HeapEnableTerminateOnCorruption()
Need To
Get Creative
In Exploitation
Methods
: Windows
Vista
and Windows
Server
2008
A Heap In Motion
Initial Heap
Heap
Management
Last Free
Chunk Header
Last Free
Chunk Space
The heap object initially starts as an
empty contiguous block of memory.
Two structures are written into the
heap.
The Heap Management structure
contains information regarding the
heap object, and tracks the heap
chunks.
There is always one Free Chunk in the
heap object and it points to the free
space at the end of the heap.
The Heap In Motion
Initial Heap
Heap
Management
Last Free
Chunk Header
Last Free
Chunk Space
Allocated
A,B,C
Heap
Management
Chunk A
Header
Chunk A Space
Chunk B
Header
Chunk B Space
Chunk C
Header
Chunk C Space
Last Free
After the allocation of
three memory chunks, the
heap layout now looks like
this
The Heap In Motion
Initial Heap
Heap
Management
Last Free
Chunk Header
Last Free
Chunk Space
Allocated
A,B,C
Heap
Management
Free B
Heap
Management
Chunk A Header
Chunk A
Header
Chunk A Space
Chunk A Space
Free Chunk
Header
Chunk B
Header
Free Chunk
Space
Chunk B Space
Chunk C Header
Chunk C
Header
Chunk C Space
Chunk C Space
Last Free Chunk
Header
Last Free
Last Free Chunk
Freeing a
chunk in
between
two busy
chunks,
creates a
Free Chunk
The Heap In Motion
Initial Heap
Heap
Management
Last Free
Chunk Header
Last Free
Chunk Space
Allocated
A,B,C
Heap
Management
Free B
Free A
Heap
Management
Heap
Management
Chunk A Header
Free Chunk
Header
Chunk A
Header
Chunk A Space
Chunk A Space
Free Chunk
Header
Chunk B
Free Chunk
Header Free chunks
that sit
Space
Chunk B Space
next to each other are
joinedChunk
(Coalesced)
C Header
together.
Chunk C
Chunk C Space
Header
Chunk C Space
Last Free Chunk
Header
Last Free
Last Free Chunk
Free Chunk
Space
Chunk C
Header
Chunk C Space
Last Free
Chunk Header
Last Free
Chunk Space
Heap Management Structure
Heap Management
Address
These
Flags
All
offsets
arehold
from
as
thesettings
base ofsuch
the Heap
The
maximum
size
isDebug,
Exceptionof
Object
an allocation
before a
Raising, and
Virtual
Memory
A four
Linked
listDWORD
of Heap
blocks
Executable
allocation
is bit
bitmask
with
allocated
fromeach
Virtual
Pointer
to
the first
performed
set
if the
Memory
chunk
in FreeList[0]
corresponding
FreeList[0]
is used
Start
of double
linked
FreeList[n]
is to
Pointer
toFree>
store
Free
Chunks
lists
to
store
populated
Pointer to Function()
CriticalSection
that is
1016
bytes
Chunks
thatto
is lock
called
when
used
the
heap
Pointer
to
the
front
theduring
heap ischanges
expanded
endmore
allocator.
and
pages
Pointer
Flag
to the
stores
Last
This
iscommitted
a that
pointer
the
Start
of
the 48 to
byte
settings
FreeLookaside
Chunk
about
in the
the
Lookaside
list headers
front end
heap
allocator
003600
00
Value
Description
Base Address
003600
0C
0000000 Flags
2
003600
10
0000000 ForceFlags
0
003600
14
0000FE0 VirtualMemoryThresh
0
old
003600
50
0036005 VirtualAllocatedBlock
0
s List
003601
58
0000000 FreeList Bitmap
0
003601
78
00361E9 FreeList[0]
0
003601
80
0036018 FreeList[n]
0
003605
78
0036060 HeapLockSection
8
Heap Management Structure - Virtual Memory Allocation
Heap Management
EBX is set to Base
Address
Check threshold
Address
Value
Description
003600
14
0000FE0 VirtualMemoryThresh
0
old
003600
50
0036005 VirtualAllocatedBlock
FLINK
0
s0036005
List
0
7C82AE14 CMP EDI,DWORD PTR DS:
0036005
BLINK
[EBX+14]
4
7C82AE17 JBE ntdll.7C82A2FC
...
Load BLINK
7C82AE8E LEA EAX,DWORD PTR DS:
[EBX+50]
...
ECX is @NewChunk
7C82AE97 MOV EDX,DWORD PTR DS:
[EAX+4]
...
Write @NewChunk to
7C82AEA0 MOV DWORD PTR DS:
@BLINK+4
[ECX],EAX
If the VirtualAllocatedBlocks->BLINK
can be overwritten then
7C82AEA2
MOV DWORD PTR DS:
the address of the NewChunk can be written to an arbitrary
[ECX+4],EDX
7C82AEA5 MOV DWORD PTR DS:location
[EDX],ECX
Heap Management Structure - FreeList Bitmap
Heap Management
Address
Bitmap is populated
when chunk added to
FreeList[n]
8
0
0
0
0-7
0
0
0
2
2431
0
0
0
0
8
0
4855
003601
58
0
0
0
0
0
0
Value
Description
0000000 FreeList Bitmap
0
0
0
7C82A291 LEA ESI,DWORD PTR DS:
[EBX+EDX*4+158]
...
7C82A2A8 AND EAX,DWORD PTR DS:[ESI]
...
7C82A2B8 JNZ ntdll.7C82CB46
7C82A2BE TEST EAX,EAX
7C82A2C0 JNZ ntdll.7C82C8C9
7C82A2C6 MOV EAX,DWORD PTR DS:[ESI]
0
0
0
0
0
0
0
0
00
Bitmap is checked
when looking for a
FreeList[n] that fits
the request
If a match is found
then the
corresponding
FreeList[n] is used for
the allocation.
If the Bitmap can be manipulated then a pointer to an empty
FreeList[n] can be returned, allowing the overwrite of
management structures. [nico]
Heap Management Structure - FreeList Bitmap
Heap Management
Address
FreeList[7] is
populated
8
0
0
0
0
0
1
0
2
0
0
003601
58
0
0
8
0
FreeList[16] is
Modify bitmap
empty
0
0
0
0
0
0
Value
0000000 FreeList Bitmap
0
0
0
0
0
0
0
0
0
0
0
00
FreeLists
Address
003601
B0
Request for block 16
Request for block 16
will create a new
will return 003601F8
block and return it
Description
...
003601
F8
Value
Description
00364D FreeList[7]
78
...
...
XXXXXX
003601 Overwrite
FreeList[16]
XX
F8
XXXXXX Overwrite
XX
If the Bitmap can be manipulated then a pointer
to an
empty
XXXXXX
Overwrite
FreeList[n] can be returned, allowing the overwrite
of
XX
management structures. [nico]
XXXXXX Overwrite
XX
Heap Management Structure - FreeList Bitmap
Part Of The Bitmap Loading Code
7C82C8AB MOVZX EAX,AH
7C82C8AE MOVSX EAX,BYTE PTR DS:
[EAX+7C82BAB8]
7C82C8B5 ADD EAX,8
7C82C8B8 JMP ntdll.7C82C830
[ 7C82BAB8 ]
7C82C8BD MOVSX EAX,BYTE PTR DS:
A Static Pointer To A
[ECX+7C82BAB8]
Bit Mask Table That
7C82C8C4 JMP ntdll.7C82C830
7C82C8C9 LEA EDX,DWORD PTR DS:
Can Be Modified To
[EBX+178]
Manipulate The
7C82C8CF JMP ntdll.7C82C808
Bitmap Result
7C82C8D4 SHR EAX,18
7C82C8D7 MOVSX EAX,BYTE PTR DS:
[EAX+7C82BAB8]
7C82C8DE ADD EAX,18
If the Bitmap
can be manipulated then a pointer to an empty
7C82C8E1
JMP ntdll.7C82C830
FreeList[n] can be returned, allowing the overwrite of
management structures. [nico]
Heap Management Structure FreeList[n]
Heap Management
FreeList[0] is similar
to FreeList[n] but
holds chunks > 1016
bytes
Address
Value
003601
78
00361e9 FreeList[0]
0
003601
80
0036018 FreeList[n]
0036018
0
0
0036018
4
Free Chunk Header
Header
Links
Self
Size
Prev
Size
CK
FLINK
FL
U
N
Links
Self
Size
Prev
Size
FLINK
FLINK
BLINK
SI
BLINK
Free Chunk Header
Header
Description
CK
FL
U
N
BLINK
SI
Double Linked
List connects
free chunks
together
Heap Management Structure - Commit Routine Pointer
Heap Management
Custom function()
called when
committing more
memory to the Heap
Address
003605
7C
Value
Description
0000000 Commit Routine Ptr
0
Initially set to nothing
7C833BF9 MOV ECX,DWORD PTR DS:
[EAX+57C]
7C833BFF TEST ECX,ECX
7C833C01 JNZ ntdll.7C852C9E
...
7C852C9E PUSH EBX
7C852C9F LEA EDX,DWORD PTR SS:
[EBP+14]
7C852CA2 PUSH EDX
7C852CA3 PUSH EAX
7C852CA4 CALL ECX
Loaded into ECX and
called
This is a static pointer that can be overwritten to gain
execution control
Heap Management Structure Lookaside[n]
Heap Management
Lookaside[0] and
Lookaside[1] are not
used
Lookaside List Header
Addres
s
+04
Depth
+06
Max Depth
+08
...
Description
0000000 Lookaside[n]
0
003606
48 byte
E8
Lookaside[2]
structure
Lookaside Chunk Header
Pointer To First
Chunk
+10
003606
88
Value
Description
+00
+0C
Address
Allocation
tracking for
automatic
Lookaside Fine
Tuning
Header
Links
Self
Size
Prev
Size
CK
FL UN
SI
FLINK
Lookaside Chunk Header
Header
Links
Self
Size
Prev
Size
FLINK
CK
FL UN
SI
Heap Chunks
A Used Chunk
Header
Self
Size
Prev
Size
CK
Chunk Flags
FL UN
SI
Data
Chunk On Lookaside
Header
Links
Self
Size
Prev
Size
CK
FL UN
SI
FLINK
Data
Chunk On FreeList
Header
Links
Data
Self
Size
Prev
Size
FLINK
CK
FL UN
BLINK
SI
00
Free
01
Busy
02
Extra Present
04
Fill Pattern
08
Virtual Alloc
10
Last Entry
20
FFU1
40
FFU2
80
No Coalesce
Lookaside Lists
Lookaside
Starts Empty
Chunk
Lookaside[n]Chunk
Removed
Added
From
>FLINK
To Top
Topis
Of
Of
Lookaside
corrupted
Lookaside
About To Allocate
Overwrite the FLINK of
From The
the top chunk
Lookaside[n]
Lookaside[n]
FLINK
0000000
0036210
003620E
XXXXXX
003620
D0
XX
0
8
Address
FLINK
003621 003620E
003620
0000000
XXXXXX
003620
D0
00
E8
D0
XX
0
8
Address
FLINK
This
Copied
Value
To
GetsHere
Copied
003620 0000000
003620
D0
E8
D0
0
Address
FLINK
003620
D0
0000000
0
There is no Safe Unlinking or Cookie check for Lookaside Lists
Well known attack is to overwrite the FLINK of a chunk on a
Lookaside. This will populate the Lookaside[n]->FLINK with an
arbitrary value to be returned at allocation.
Freelist[n] Lists
Freelist
Freelist
Starts
Is
Empty
Chunk Added
To Bottom
Chunk
Chunk Added
Removed
To Bottom
From Bottom
Freelist[n]
Lookaside[n]
Address
FLINK
BLINK
FLINK
0000000
0036210
003620E
003620
D0
0
8
003601 003621
003601
003601
003621
90
90
30
90
60
30
Address
FLINK
BLINK
003621
30
Address
003601
003621
60
90
FLINK
003601
90
BLINK
003621
60
003601
90
003621
30
Safe Unlinking and Cookie checks will prevent Unlinking
Overwriting the Freelist[n]->BLINK will cause the address of
the Freed Chunk to be written to an arbitrary location
Freelist[n] Lists
Freelist Searching
: If a freelist[n] of requested size not available
bitmap is used to find larger populated
freelist[n]
Chunk Size
: Size field of the chunk header used as offset to
bitmap
: Bitmap is updated on allocate/free if needed
: Size field is used to calculate freelist[n] to free
to
Manipulating Size Field
: Allocation can control bitmap flipping
Header
Self
Prev
CK FL UN SI
: Free can have chunk
freed
to
different
Size
Size
lookaside/freelist
Flipping Bitmap On Allocate
Size Is Overwritten
FLINK / BLINK Can Be
Overwritten
Chunk On FreeList
Header
####
Links
Prev
Size
FLINK
CK
FL UN
SI
BLINK
Data
7C82C8E6 MOVZX ECX,WORD PTR DS:[ESI]
; Load
Self Size
7C82C8E9 MOV EDX,ECX
..
7C82C902 8DBC1A 58010000 LEA EDI,DWORD PTR DS:
If Last Chunk[EDX+EBX+158]
On Freelist Then Bitmap
Updated
If FLINK and BLINK Overwritten with
Valid For Read and
FLINK == BLINK
Then Bitmap Updated
Bitmap Attack Explained Earlier
Calculate
Bitmap
Free To Arbitrary Lookaside[n]/FreeList[n]
Chunk To Be Freed
Size Is Overwritten
Cookie Is Left Intact
Header
####
Prev
Size
CK
FL UN
SI
Data
Freeing To
Freeing To
Lookaside[n
Freelist[n]
]
7C82A84C MOVZX
7C829F1B
MOVZX EAX,WORD
EAX,WORD PTR
PTR DS:[ESI]
SS:[EBP-20] ; Load
self size
selfsize
7C829F1E MOV
7C82A850
LEA EBX,DWORD
DWORD PTR PTR
SS:[EBP-20],EAX
DS:[EDI+EAX*8+178] ;
7C829F217C82A857
Calculate
CMP EAX,80
MOV DWORD PTR SS:[EBP-88],EBX
7C829F26 JNB
7C82A85D
CMPntdll.7C82A7BC
DWORD PTR DS:[EBX],EBX
; Check
7C829F2C PUSH DWORD PTR SS:[EBP+10]
Freelist
7C829F2F
LEA Is
EAX,DWORD
DS:[EAX+EAX*2]
Coalescing
A ProblemPTR
That
Needs To Be Dealt ;
Calculate Lookaside
With
7C829F32 SHL EAX,4
7C829F35 ADD EAX,ECX
7C829F37 PUSH EAX
7C829F38 CALL ntdll.7C829F8F
; Push to
Lookaside
Could This Be Useful When Filling In Gaps?
FreeList[0] - Free
Freelist[0]
Populate
d
Freelist[
0]
Address
FLINK
BLINK
003601
78
Address
00361E
90
FLINK
00362B
60
BLINK
00361E
90
Address
003622
D0
FLINK
003601
78
BLINK
003622
D0
Address
00362B
60
FLINK
00361E
90
BLINK
00362B
60
003601
78
003622
D0
Load Freelist[0]>FLINK
Check Size Is Larger
Not
Load
ThanGreater,
Chunk Been
Chunk->FLINK
Freed
Check Size Is Great
Chunk Been
IfThan
It Is Greater
Then
Freed
Insert
Chunk
Exploitable Condition On Freelist[0] Insert
Exploiting FreeList[0] - Free
An Overwritten Chunk In Freelist[0] Can Be Exploited To
Write The Address Of The Chunk Being Freed To An Arbitrary
Location
7C82A982 CMP DX,WORD PTR DS:[EAX]
7C82A985 JA ntdll.7C82FDC4
next
; Compare chunk size
; To large move to
7C82A98B LEA EAX,DWORD PTR DS:[ESI+8]
; Header of freed
chunk
7C82A98E MOV DWORD PTR SS:[EBP-7C],EAX
7C82A991 MOV EDX,DWORD PTR DS:[ECX+4] ; Load BLINK of
current chunk
7C82A994 MOV DWORD PTR SS:[EBP-84],EDX
7C82A99A MOV DWORD PTR DS:[EAX],ECX
; Set freed->FLINK
== current
7C82A99C MOV DWORD PTR DS:[EAX+4],EDX ; Set freed->BLINK
==current->BLINK
7C82A99F MOV DWORD PTR DS:[EDX],EAX
; Write @freed to
Exploitable Condition On Freelist[0]
Insert
[current->BLINK]
7C82A9A1 MOV DWORD PTR DS:[ECX+4],EAX ; Set current->BLINK
Exploiting FreeList[0] - Free
Chunk To Be Freed @003622D0
8400
Prev
Prev
Size
Size
00361E90
CK
FL
FL UN
UN
SI
Chunk Is Inserted Before The
Overwritting Chunk.
FLINK and BLINK updated
Overwritten Chunk
@00361E90
00360718
FFFF
????
??
FFFFFFFF
02
??
003622D0
00360718
Place Where We Want To Write
003622D0
Could Be A Function Table, This Is A
Overwritten Lookaside Now
Lookaside
Populated
Three Requests And We Get Our Set
Location
Exploitable Condition On Freelist[0] Insert
??
FreeList[0] - Allocate
Freelist[0]
Populate
d
Freelist[
0]
Address
FLINK
BLINK
003601
78
Address
00361E
90
FLINK
00362B
60
BLINK
00361E
90
Address
003622
D0
FLINK
003601
78
BLINK
003622
D0
Address
00362B
60
FLINK
00361E
90
BLINK
00362B
60
003601
78
003622
D0
Load Freelist[0]>BLINK
>FLINK
Check Size Is Large
Too For
Small,
Enough
Request
Load Chunk->FLINK
Check Size Is Large
LargeFor
Enough,
Enough
Request
Return Chunk
Check Size Is Large
Enough For Request
Exploitable Condition On Freelist[0] Allocate
Exploiting FreeList[0] - Searching
Request Made For Size
0x0BF8
Chunk Returned To
Caller
This Address Is In
The Freelists
Overwritten Chunk
@003622C8
0100
????
00360188
??
??
??
????????
FLINK Points To
Fake
FakeChunk+8
Chunk
Fake Chunk @00360180
8001
3600
00360188
= Requested Size
(+1 block)
??
80
01
36
00
00360188
Must Be Readable
Exploitable Condition On Freelist[0] Allocate - Searching
Allocation Relinking
If Chunk Is Larger
Than Request It Will
Get Split
Chunk Header Chunk Header
Chunk Space Chunk Space
New Chunk New Chunk
Header
Header
Chunk Returned To
Caller
New Chunk New Chunk
Space
Space
New Header Is
Written Into The
Existing Chunk
Space
Chunk Inserted
Into FreeLists
Exploiting FreeList[0] - Relinking
Request Made For Size
Smaller Than Our
Overwrite
Relink Chunk
Address Written To
00360580
This Is The
FrontEndHeap
(Lookaside Base)
> Relink Chunk
Size
Overwritten Chunk
@003622C8
0202
????
??
0036057C
??
??
??
READ
XXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
FLINK Points To
XXXXX.....
Fake
FakeChunk+8
Chunk
Fake Chunk @00360574
7005
3600
????????
08
06
36
00360688
Must Be
Read/Write
Exploitable Condition On Freelist[0] Allocate - Relinking
00
Splitting / Resizing
When Allocated Chunk Is To Large
: Checked when allocation from other list
: Chunk is cut to size, New header is written
: Chunk is inserted to freelist[n] or freelist[0]
: Size manipulated to put new chunk into
arbitrary
Freelist
7C82A3DB
CMP EBX,1
; Larger than one block
difference
7C82A3DE JE ntdll.7C82E5A4
7C82A3E4 MOV EAX,DWORD PTR SS:[EBP-48] ; Load requested size
7C82A3E7 LEA EDI,DWORD PTR DS:[ESI+EAX*8]
; Move to
create the new chunk
Can Skip By
..
7C82A3F3 MOV BYTE PTR DS:[EDI+5],CL
; Store new
Setting
flag As Last
7C82A3F6 MOV WORD PTR DS:[EDI+2],AX
; Store Prev Size
Chunk
..
7C82A400 MOV WORD PTR DS:[EDI],BX
; Store new size
7C82A403 TEST CL,10
; Is chunk new LAST CHUNK
7C82A406 JNZ ntdll.7C82A65E
; Jump if chunk is last chunk
7C82A40C LEA EAX,DWORD PTR DS:[EDI+EBX*8]
; Move to
NEXT chunk based on size
Coalesced Chunks
When Chunk Is Freed To Freelist
: Size field is used to locate previous and next
chunk
Test Flag
: Requires valid FLINK/BLINK on chunks to
Of
colaesce
Previous
7C82A6F6 JE SHORT ntdll.7C82A702
; If prev size is 0 jump
Chunk
7C82A6F8 TEST BYTE PTR DS:[ESI+5],1
; Is prev chunk BUSY?
7C82A6FC JE ntdll.7C82CA7A
; If not then coalesce
7C82A702 TEST BYTE PTR DS:[EDI+5],10
; Is our chunk
the last chunk?
Test Flag
7C82A706 JNZ ntdll.7C82A7B3
; If so can't coalesce
7C82A70C MOV EAX,DWORD PTR SS:[EBP+10]
Of Next
7C82A70F MOV EAX,DWORD PTR DS:[EAX]
; Load our block size
Chunk
7C82A711 LEA ESI,DWORD PTR DS:[EDI+EAX*8]
; Move to
next chunk
7C82A714 TEST BYTE PTR DS:[ESI+5],1
; Is next chunk BUSY?
7C82A718 JNZ ntdll.7C82A7B3
; Yup, so don't colaesce
: An overflow can control all of this to prevent
Self
Prev
CK FL UN SI
coalesce Header Size
Size
Preventing Coalesce
How To Prevent A Coalesce
: Set the chunk being freed prev size to ZERO
: Set the chunk being freed FLAG to last
chunk
: Set the chunk being freed self size > 0xFE00
: Set the prev/next chunks flag to PASS the
BUSY check
: Control the size to fake the prev/next
chunks location
Why Prevent A Coalesce()
: Coalescing an overwritten chunk normally
blows up
: Linking, resizing, and relinking is very
complex
Coalesced Chunks
????
????
??
??
??
??
Chunk A
Data Stored In
DATA
BUSY
Chunk
FFFF
BUSY
Chunk
Chunk A Will Be
Freed And We
Want To Prevent
Coalescing
FFFF
FF
DATA
01
FF
FF
FF
Chunk B
We
Overflowing
Keep The Flag
Set To BUSY
Coalesced Chunks
????
????
??
??
??
??
Chunk A
Data Stored In
DATA
BUSY
Chunk
FFFF
FFFF
FF
01
FF
FF
FF
FF
FF
01
FF
FF
DATA
0200
FFFF
BUSY
Chunk
0200
FFFF
FF
DATA
FFFF
Chunk B Will Be
Freed And We
Want To Prevent
Coalescing
FFFF
FF
DATA
Create Two Fake Chunks
And Set Size In Header
Of Chunk B To Point To
The Fake Chunks
Flag Set To Busy
Chunk B
We
Overflowing
Coalesced Chunks
????
????
??
??
??
??
Chunk A
Data Stored In
DATA
BUSY
Chunk
FFFF
BUSY
Chunk
Chunk B Will Be
Freed And We
Want To Prevent
Coalescing
0000
FFFF
FF
DATA
10
FF
FF
FF
Chunk B
We
Overflowing
Set The Flag To
Contain The
Last Chunk
Flag
Preventing A Free
How To Prevent A Free
: Set the chunks flag to FAIL the BUSY check
Move To
Chunk Header
Load Flag and
Test If Busy
Why Prevent A Free()
: Remove chunk from Lookaside
Can be overwritten before allocation
: Remove chunk from Freelist[]
Flag gets reset on allocation
Bypass Cookie Check
: Will cause a heap exception, doesnt stop
execution
Example Removing Chunk From Lookaside
Before
Allocation
Overwrite Flag
Self
Size
Prev
Size
CK
FL UN
SI
Self
Size
Prev
Size
CK
FL UN
SI
0300
0300
06
01
00
0101
0101
01
02
01
After
Allocation
After Free()
0E
01
Clearing The Lookaside
Top Chunk On A Lookaside Is Overwritten
: Flags set to not BUSY, Flink set to
0x00000000
Before
Allocation
Overwrite Flag And FLINK
Self
Size
Prev
Size
CK
FL UN
SI
Self
Size
Prev
Size
CK
FL UN
SI
0300
0300
06
01
00
0101
0101
01
02
01
00362100
0E
00000000
After
Overwrite
Allocation And Free Will Clear The Lookaside List
01
The Exploitation Process
The Steps
: Exploit the heap
: Overwrite a function pointer or other to gain
execution
: Flip the heap onto the stack to get ret-tolibc style control
: Turn off Data Execution Protection (DEP)
: Return to shellcode
Exploit The Heap
: Application dependant
Overwrite A Function Pointer
: Application dependant?
Heap / Stack Flipping
What Is Heap/Stack Flipping
: Exploit data is on the heap
: For fine grained control, it needs to be on
the stack
Requirements
: Pointer to exploit data; on stack, in a
register, in [reg +/- n]
: Locate instructions to manipulate pointer
and pop esp, ret
EBX ->
EBP ->
ECX ->
EAX->
: Overwrite
function
pointer
to
return
DATA
DATA
DATA
DATAto
instructions
PUSH
EBX
LEAVE
MOV
XCHG
POP ESP
RET
ESP,ECX
EAX,ESP
Populate
ESP
With
The
Pointer
To
Exploit Data
POP EBP
RET 8
RET
RET
Heap / Stack Flipping
Exploit Data
Stack
Registers
Code Gets
Executed
Flipping Code
Heap / Stack Flipping
Exploit Data
New Registers
New Stack
Code That We Returned
Into
Bypassing DEP
Entirely Ret-to-Libc
: Entire shellcode in borrowed instructions
: Inject into process that is not DEP enabled
: Very difficult
HeapCreate()
: Create new heap with
HEAP_CREATE_ENABLE_EXECUTE
: Allocate new chunk, memcpy shellcode across
: Doable, but sounds like a lot of work
Registry
: 'Image File Execution Options
: Would turn it off on a restart
: Not really very helpful
Bypassing DEP
SetProcessDEPPolicy()
: Not available on 2003
Copy Shellcode To RWE Memory Page
: Copy shellcode and then return to address
VirtualProtect()
: Use the PAGE_EXECUTE_READWRITE flag to
reset heap
: Return to shellcode
Bypassing DEP
VirtualAlloc()
: Allocate new memory with
PAGE_EXECUTE_READWRITE
: Address is returned in EAX
: Copy shellcode and return to it
NtSetInformationProcess()
: Skape and Skywing ret-to-libc to deactivate
DEP
: Easier on windows 2003
NtSetInformationProcess(
NtCurrentProcess(), //
(HANDLE)-1
ProcessExecuteFlags, //
0x22
&ExecuteFlags, // ptr to 0x2
sizeof(ExecuteFlags)); // 0x4
Bypassing DEP
Perfect
Instruction
Set
BUT!
Requires [ESI+37] To Be
Writable
Correctly Set Stack
NtSetInformationProcess(
NtCurrentProcess(), //
(HANDLE)-1
ProcessExecuteFlags, //
0x22
&ExecuteFlags, // ptr to 0x2
sizeof(ExecuteFlags)); // 0x4
Heap Exploitation
Step By Step
: The vulnerability
: Reproduction
: Understanding the bug
: Finding an overwrite
: Find a pointer
: Flipping the heap to stack
: Bypassing DEP
: The working
The Vulnerability
Citrix
Citrix
ImaSrv.exe
TCP Port 2512 or 2513
User-supplied -> Memory
Allocation
Undersized Allocation
Overflow The Heap Buffer
TCP Port 2512 or
2513
Overflow The Heap
Buffer
ImaSrv.e
User-suppliedxe
-> Memory
Allocation
Reproducing The Vulnerability
Usual Integer Overflow
: Usual packet size bug
Length Of
Data
DATA
Usual Basic Fuzz Test
while !crashed
{
inc buffer length
fill buffer with 0xFF
send to TCP 2512
}
\
xFF\xFF\xFF\x
FF
\
xFF\xFF\xFF\xFF\xFF\xF
F
I Am
Listening
On TCP
2512
Reproducing The Vulnerability
ntdll!A RtlAllocateHeap
Crash
In the good ol days, it would now be as easy as overwriting
the UEF.
But those days are over.
Understanding The Bug
Need To Trace From Start To FinishWSARecv
: bp WSARecv and send overflow again
Stack
Buffer Size
Buffer Address
Understanding The Bug
Need To Trace From Start To Finish
: After WSARecv our buffer is loaded
Understanding The Bug
Trace Through Code To Determine Paths
: This code checks buffer sizes
Load First DWORD
Of Packet Into EAX
Jump If Our Packet
Specified A Size
Larger Than 0x408
Compare Against
Size Of Current
Buffer 0x408
Understanding The Bug
Trace Through Code To Determine Paths
ESI == First
: Eventually get to here
DWORD From
Packet
EAX == ESI
+ 3C
Is Going To
Allocate A
Buffer Of Size
EAX
Understanding The Bug
But its not over yet
: Trace down to ntdll!RTLAllocateHeap
Allocate From Heap
00320000
Allocate 3B Bytes
Understanding The Bug
Still Thats Just An Undersized Buffer
: Keep tracing the code
EAX Points To The
Newly Allocated
Buffer
Bunch Of Stuff Is
Written Into The New
Buffer
This Is A Custom
Header And Is 0x3C
Bytes Long
Understanding The Bug
Finally....
: A memmove instruction overflows the buffer
New
Buffer+3C
Packet Data
KABOOM!
This Is The Size Of
The Packet That We
Sent
Understanding The Bug
The Result
: We can cause the allocation of a size 0x01
0x03B
: We can overflow the chunk with 0x408 bytes
The Limitations
: Can only allocate chunk 2 through to 9
That range is
FFFFFFC5 == 0x01 ==
Chunk 2
To
FFFFFFFF == 0x3b ==
Chunk 9
: The first 0x3C bytes are not controlled by us
due to the custom header
The Request LifeCycle
RTLAllocateHea
p()
WSARecv()
memmove()
RTLFreeHeap()
So Now What?
: We know we can cause an allocation of a lower
chunk
: Lets look at the Lookaside lists at the time of the
allocation
The Lookaside Lists
0x0a871c38
0x0a871bd0
= 0x68
Lookaside[8] Has A Top Chunk
That Sits After Lookaside[7] Top
Chunk On All Runs
AND
The Difference Is Greater Than
0x3C
0x0a871cc8
0x0a871c60
= 0x68
0x0a871d00
0x0a871c98
= 0x68
Lets Try It
First Request
: Request Lookaside[7]
: Overwrite Lookaside[8]
: Free Request
Problem
: If we now had two allocations of Lookaside[8]
: But we only have one
Solution
: Set flag of top chunk of Lookaside[8] to be
FREE
: Then when free() is called it will be skipped
Lets Try It
First Request
: Request Lookaside[7]
: Overwrite Lookaside[8]
: Free Request
Second Request
: Request Lookaside[8]
: Top Chunk Is Popped
: Free Request
Third Request
: Request Lookaside[8], Our Address Is
Returned
What Address To Overwrite
Function Pointer
: Trace code looking for pointer
: None found before WSARecv()
Lucky For Us That
Winsock Uses Static
Pointers
EAX Points To
Stack
0x71C14044 Is A Static
Pointer That Can Be
Overwritten
Winsock Structure
Winsock
: Holds a structure
Static
Pointer To
Handle
: Structure holds pointer to function pointer
table on the default heap
Load Address Of
Pointer Table
Static Within
Heap
Call Function
Exploiting The Bug
Pointer Table Address
: 0x142360
Set Lookaside Address
: Need to account for header
: Set lookaside to 0x01431D0
Heap/Stack Flip Local
Overwrite The Pointer Table
To Citrix DLLS
: We now control execution
Set The Stack
: EAX points to the pointer table
: EAX points to our data
: Search for a heap/stack flip
Return Down The Stack
: Return to Anti-DEP
: Return to shellcode on pointer table
Da Greetz
Acknowledgement to those who shared
current information, some of which was used
in this presentation
Nico
Caddis
mxatone
Acknowledgement to those who have
published past heap research
0ded
Shok
Sotirov
Sandip Chaudhari
A. Anisimov
N. Falliere
Halvar
Litchfield
+ All Others