Heaps about Heaps

Download Report

Transcript Heaps about Heaps

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()
: Windows Vista and Windows Server 2008
Need To Get Creative In Exploitation Methods
A Heap In Motion
Initial Heap
Heap Management
The heap object initially starts as an empty
contiguous block of memory.
Last Free Chunk
Header
Two structures are written into the heap.
Last Free Chunk
Space
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
Allocated A,B,C
Heap Management
Heap Management
Last Free Chunk
Header
Chunk A Header
Last Free Chunk
Space
Chunk A Space
Chunk B Header
Chunk B Space
Chunk C Header
Chunk C Space
Last Free Chunk
Header
Last Free Chunk
Space
After the allocation of three
memory chunks, the heap layout
now looks like this
The Heap In Motion
Initial Heap
Allocated A,B,C
Free B
Heap Management
Heap Management
Heap Management
Last Free Chunk
Header
Chunk A Header
Chunk A Header
Chunk A Space
Chunk A Space
Chunk B Header
Free Chunk Header
Chunk B Space
Free Chunk Space
Chunk C Header
Chunk C Header
Chunk C Space
Chunk C Space
Last Free Chunk
Header
Last Free Chunk
Header
Last Free Chunk
Space
Last Free Chunk
Space
Last Free Chunk
Space
Freeing a
chunk in
between two
busy chunks,
creates a Free
Chunk
The Heap In Motion
Initial Heap
Allocated A,B,C
Free B
Free A
Heap Management
Heap Management
Heap Management
Heap Management
Last Free Chunk
Header
Chunk A Header
Chunk A Header
Free Chunk Header
Chunk A Space
Chunk A Space
Free Chunk Space
Chunk B Header
Free Chunk Header
Chunk B Space
Free Chunk Space
Chunk C Header
Chunk C Header
Last Free Chunk
Space
Free chunksChunk
that sit
next to
Chunk C Space
C Space
each other are joined
together.
Last Free Chunk(Coalesced)
Last Free
Chunk
Chunk C Header
Chunk C Space
Header
Header
Last Free Chunk
Header
Last Free Chunk
Space
Last Free Chunk
Space
Last Free Chunk
Space
Heap Management Structure
Heap Management
Address
These
Flagsare
hold
settings
All offsets
from
the
such
Exception
baseasofisDebug,
the Heap
Object
The
maximum
size
of an
Raising, and Executable
allocation Heap
before a Virtual
Linked list
of blocksis
Memory
allocation
Aallocated
four DWORD
from bitmask
Virtual
performed
with each
setchunk
if the in
Pointer
toMemory
thebitfirst
corresponding
FreeList[n] is
FreeList[0]
FreeList[0]
is used
to store
Start of populated
double
linked
lists
Pointer
to Free
CriticalSection
Free
Chunks
> 1016
bytes
to
store
Chunks
Pointer
to
Function()
that is used to lock that
the is
called
heap
is
heapwhen
during
changes
Pointer
to thethe
front
end
expandedallocator.
and more pages
Flag
that
stores settings
This
iscommitted
aof
to
the
Pointer
Start
topointer
the
the48
Last
byte
Free
aboutLookaside
the front end
Lookaside
Chunk inlist
theheaders
heap
allocator
Value
00360000
Description
Base Address
0036000C
00000002
Flags
00360010
00000000
ForceFlags
00360014
0000FE00
VirtualMemoryThreshold
00360050
00360050
VirtualAllocatedBlocks List
00360158
00000000
FreeList Bitmap
00360178
00361E90
FreeList[0]
00360180
00360180
FreeList[n]
00360578
00360608
HeapLockSection
0036057C
00000000
Commit Routine Ptr
00360580
00360688
FrontEndHeap
00360586
00000001
FrontEndHeapType
00360678
00361E88
Last Free Chunk
00360688
00000000
Lookaside[n]
Heap Management Structure - Virtual Memory Allocation
Heap Management
EBX is set to Base Address
Check threshold
Address
Value
Description
00360014
0000FE00
VirtualMemoryThreshold
00360050
00360050
VirtualAllocatedBlocks List
7C82AE14 CMP EDI,DWORD PTR DS:[EBX+14]
7C82AE17 JBE ntdll.7C82A2FC
...
7C82AE8E LEA EAX,DWORD PTR DS:[EBX+50]
...
7C82AE97 MOV EDX,DWORD PTR DS:[EAX+4]
...
7C82AEA0 MOV DWORD PTR DS:[ECX],EAX
7C82AEA2 MOV DWORD PTR DS:[ECX+4],EDX
7C82AEA5 MOV DWORD PTR DS:[EDX],ECX
7C82AEA7 MOV DWORD PTR DS:[EAX+4],ECX
00360050
FLINK
00360054
BLINK
Load BLINK
ECX is @NewChunk
Write @NewChunk to
@BLINK+4
If the VirtualAllocatedBlocks->BLINK can be overwritten then the address of
the NewChunk can be written to an arbitrary location
Heap Management Structure - FreeList Bitmap
Heap Management
Bitmap is populated when
chunk added to FreeList[n]
80
00
0-7
00
02
00
24-31
00
80
00
Address
Value
00360158
00000000
00
00
00
48-55
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]
00
Description
FreeList Bitmap
00
00
00
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
FreeList[7] is
populated
80
00
00
01
02
00
00
80
FreeList[16] is
Modify bitmap
empty
00
Address
Value
00360158
00000000
00
00
00
00
Description
FreeList Bitmap
00
00
00
00
FreeLists
Address
Value
Description
003601B0 00364D78 FreeList[7]
Request for block 16 will
Request for block 16 will
create a new block and
return 003601F8
return it
...
003601F8
...
...
XXXXXXXX
003601F8 Overwrite
FreeList[16]
XXXXXXXX Overwrite
XXXXXXXX Overwrite
XXXXXXXX Overwrite
XXXXXXXX Overwrite
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
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
7C82C8BD MOVSX EAX,BYTE PTR DS:[ECX+7C82BAB8]
7C82C8C4 JMP ntdll.7C82C830
7C82C8C9 LEA EDX,DWORD PTR DS:[EBX+178]
7C82C8CF JMP ntdll.7C82C808
7C82C8D4 SHR EAX,18
7C82C8D7 MOVSX EAX,BYTE PTR DS:[EAX+7C82BAB8]
7C82C8DE ADD EAX,18
7C82C8E1 JMP ntdll.7C82C830
[ 7C82BAB8 ]
A Static Pointer To A Bit
Mask Table That Can Be
Modified To Manipulate
The Bitmap Result
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[n]
Heap Management
FreeList[0] is similar to
FreeList[n] but holds
chunks > 1016 bytes
Address
Value
Description
00360178
00361e90
FreeList[0]
00360180
00360180
FreeList[n]
00360180
FLINK
00360184
BLINK
Free Chunk Header
Header
Links
Self Size
Prev Size
CK
FLINK
FL
UN
SI
BLINK
Free Chunk Header
Header
Links
Self Size
Prev Size
FLINK
CK
FL
UN
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
Value
Description
0036057C
00000000
Commit Routine Ptr
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
Address
Description
+00
Pointer To First Chunk
+04
Depth
+06
Max Depth
Address
Value
Description
00360688
00000000
003606E8
Lookaside[n]
Lookaside[2]
48 byte structure
Lookaside Chunk Header
Header
Links
Self Size
Prev Size
CK
FL
UN
SI
FL
UN
SI
FLINK
+08
+0C
+10
...
Allocation tracking for
automatic Lookaside
Fine Tuning
Lookaside Chunk Header
Header
Links
Self Size
Prev Size
FLINK
CK
Heap Chunks
A Used Chunk
Header
Self Size
Prev Size
Chunk Flags
CK
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]->FLINK
Chunk
Removed
Added
From
To
TopTop
is Of
corrupted
Of
Lookaside
Lookaside
About
Overwrite
To Allocate
the FLINK
From
of the
The
Lookaside[n]
top chunk
Lookaside[n]
FLINK
003620D0
XXXXXXXX
00000000
00362100
003620E8
Address
FLINK
003620D0
00362100
003620E8
003620D0
XXXXXXXX
00000000
003620E8
Address
FLINK
003620D0
003620E8
003620D0
00000000
Address
FLINK
003620D0
00000000
This Value Gets
Copied To Here
Copied
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 Starts
Freelist Is Empty
Empty
Freelist[n]
Lookaside[n]
Address
FLINK
FLINK
003620D0
00000000
00362100
003620E8
BLINK
00360190 00362130
00360190 00362130
00360190
00362160
Chunk Added To
Bottom
Address
FLINK
BLINK
00362130 00360190
00362160 00360190
Chunk Removed
Added To
From
Bottom
Bottom
Address
FLINK
BLINK
00362160 00360190 00362130
Safe Unlinking and Cookie checks will prevent Unlinking
Overwriting the Freelist[n]->BLINK will cause the address of the Free’d 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
: Free can have chunk free’d to different lookaside/freelist
Header
Self Size
Prev Size
CK
FL
UN
SI
Flipping Bitmap On Allocate
Chunk On FreeList
Size Is Overwritten
FLINK / BLINK Can Be
Overwritten
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:[EDX+EBX+158]
If Last Chunk 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
Freeing To
Lookaside[n]
Freelist[n]
Header
####
Prev Size
CK
FL
UN
SI
Data
7C82A84C MOVZX
7C829F1B
MOVZX EAX,WORD
EAX,WORD PTR
PTR DS:[ESI]
SS:[EBP-20] ; Load self
selfsize
size
7C829F1E MOV
7C82A850
LEA EBX,DWORD
DWORD PTRPTR
SS:[EBP-20],EAX
DS:[EDI+EAX*8+178] ; Calculate
7C829F21 CMP
7C82A857
MOVEAX,80
DWORD PTR SS:[EBP-88],EBX
7C829F26 JNB
7C82A85D
CMPntdll.7C82A7BC
DWORD PTR DS:[EBX],EBX
; Check Freelist
7C829F2C PUSH DWORD PTR SS:[EBP+10]
7C829F2F LEA EAX,DWORD PTR DS:[EAX+EAX*2] ; Calculate Lookaside
7C829F32 SHL EAX,4
Coalescing
Is A Problem That Needs To Be Dealt With
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]
Address
FLINK
BLINK
Load Freelist[0]->FLINK
00360178 00361E90 00362B60
Populated
Freelist[0]
Address
FLINK
BLINK
00361E90 003622D0 00360178
Address
FLINK
BLINK
003622D0 00362B60 00361E90
Address
FLINK
BLINK
Check Size Is Larger Than
Not Greater, Load
Chunk Been Free’d
Chunk->FLINK
Check Size Is Great Than
IfChunk
It Is Greater
Then
Been Free’d
Insert Chunk
00362B60 00360178 003622D0
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
; Compare chunk size
; To large move to next
7C82A98B LEA EAX,DWORD PTR DS:[ESI+8]
7C82A98E MOV DWORD PTR SS:[EBP-7C],EAX
7C82A991 MOV EDX,DWORD PTR DS:[ECX+4]
7C82A994 MOV DWORD PTR SS:[EBP-84],EDX
7C82A99A MOV DWORD PTR DS:[EAX],ECX
7C82A99C MOV DWORD PTR DS:[EAX+4],EDX
7C82A99F MOV DWORD PTR DS:[EDX],EAX
7C82A9A1 MOV DWORD PTR DS:[ECX+4],EAX
; Header of free’d chunk
; Load BLINK of current chunk
; Set free’d->FLINK == current
; Set free’d->BLINK ==current->BLINK
; Write @free’d to [current->BLINK]
; Set current->BLINK == @free’d
Exploitable Condition On Freelist[0] Insert
Exploiting FreeList[0] - Free
Chunk Is Inserted Before The
Overwritting Chunk.
FLINK and BLINK updated
Chunk To Be Freed @003622D0
8400
Prev
Prev Size
Size
00361E90
CK
FL
FL
UN
UN
SI
Overwritten Chunk @00361E90
00360718
FFFF
????
FFFFFFFF
??
02
??
003622D0
00360718
Place Where We Want To Write 003622D0
Could Be A Function Table, This Is A Lookaside
Overwritten Lookaside Now Populated
Three Requests And We Get Our Set Location
Exploitable Condition On Freelist[0] Insert
??
FreeList[0] - Allocate
Freelist[0]
Address
FLINK
BLINK
Load Freelist[0]->BLINK
Freelist[0]->FLINK
00360178 00361E90 00362B60
Populated
Freelist[0]
Address
FLINK
BLINK
00361E90 003622D0 00360178
Address
FLINK
BLINK
003622D0 00362B60 00361E90
Address
FLINK
BLINK
00362B60 00360178 003622D0
Check Size Is Large
TooFor
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
Overwritten Chunk @003622C8
Request Made For Size
0x0BF8
0100
????
??
00360188
??
??
????????
FLINK Points To Fake
Chunk+8
Chunk
Chunk Returned To Caller
This Address Is In The
Freelists
Fake Chunk @00360180
8001
3600
00360188
= Requested Size
(+1 block)
??
80
01
36
00360188
Must Be Readable
Exploitable Condition On Freelist[0] Allocate - Searching
00
Allocation Relinking
If Chunk Is Larger Than
Request It Will Get Split
Chunk Header
Chunk Header
Chunk Space
Chunk Space
New Chunk Header
New Chunk Header
New Chunk Space
New Chunk Space
Chunk Returned To
Caller
New Header Is Written
Into The Existing Chunk
Space
Chunk Inserted Into
FreeLists
Exploiting FreeList[0] - Relinking
Overwritten Chunk @003622C8
0202
Request Made For Size
Smaller Than Our Overwrite
????
??
??
READ
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX.....
FLINK Points To Fake
Chunk+8
Chunk
Fake Chunk @00360574
7005
3600
????????
> Relink Chunk Size
??
0036057C
Relink Chunk Address
Written To 00360580
This Is The FrontEndHeap
(Lookaside Base)
??
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
7C82A3DE JE ntdll.7C82E5A4
7C82A3E4 MOV EAX,DWORD PTR SS:[EBP-48]
7C82A3E7 LEA EDI,DWORD PTR DS:[ESI+EAX*8]
..
7C82A3F3 MOV BYTE PTR DS:[EDI+5],CL
7C82A3F6 MOV WORD PTR DS:[EDI+2],AX
..
7C82A400 MOV WORD PTR DS:[EDI],BX
7C82A403 TEST CL,10
7C82A406 JNZ ntdll.7C82A65E
7C82A40C LEA EAX,DWORD PTR DS:[EDI+EBX*8]
7C82A40F MOV DWORD PTR SS:[EBP-50],EAX
; Larger than one block difference
; Load requested size
; Move to create the new chunk
; Store new flag
; Store Prev Size
Can Skip By
Setting As Last
Chunk
; Store new size
; Is chunk new LAST CHUNK
; Jump if chunk is last chunk
; Move to NEXT chunk based on size
; Will try and coalesce with next
Coalesced Chunks
When Chunk Is Free’d To Freelist
: Size field is used to locate previous and next chunk
: Requires valid FLINK/BLINK on chunks to colaesce
7C82A6F6 JE SHORT ntdll.7C82A702
7C82A6F8 TEST BYTE PTR DS:[ESI+5],1
7C82A6FC JE ntdll.7C82CA7A
7C82A702 TEST BYTE PTR DS:[EDI+5],10
7C82A706 JNZ ntdll.7C82A7B3
7C82A70C MOV EAX,DWORD PTR SS:[EBP+10]
7C82A70F MOV EAX,DWORD PTR DS:[EAX]
7C82A711 LEA ESI,DWORD PTR DS:[EDI+EAX*8]
7C82A714 TEST BYTE PTR DS:[ESI+5],1
7C82A718 JNZ ntdll.7C82A7B3
; If prev size is 0 jump
; Is prev chunk BUSY?
; If not then coalesce
; Is our chunk the last chunk?
; If so can't coalesce
Test Flag Of
Previous
Chunk
; Load our block size
; Move to next chunk
; Is next chunk BUSY?
; Yup, so don't colaesce
: An overflow can control all of this to prevent coalesce
Header
Self Size
Prev Size
CK
FL
UN
SI
Test Flag
Of Next
Chunk
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 Free’d
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
FFFF
FF
DATA
Chunk B Will Be Free’d
And We Want To
Prevent Coalescing
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 Free’d
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, doesn’t 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
0E
00
0101
0101
01
02
01
01
After Allocation
After Free()
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
0E
00
0101
0101
01
02
01
01
00362100
00000000
After Overwrite
Allocation And Free Will Clear The Lookaside List
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-to-libc 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
: Overwrite function pointer to return to instructions
Populate ESP With The Pointer To Exploit Data
EBX -> DATA
PUSH EBX
POP ESP
POP EBP
RET
EBP -> DATA
LEAVE
RET
ECX -> DATA
MOV ESP,ECX
RET 8
EAX-> DATA
XCHG EAX,ESP
RET
Heap / Stack Flipping
Exploit Data
Stack
Registers
Code Gets
Executed
Flipping Code
Heap / Stack Flipping
Exploit Data
New Stack
New Registers
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
ImaSrv.exe
TCP Port 2512 or 2513
User-supplied -> Memory Allocation
Undersized Allocation
Overflow The Heap Buffer
Citrix
TCP Port 2512 or 2513
Overflow The Heap Buffer
ImaSrv.exe
User-supplied -> 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\xFF
\xFF\xFF\xFF\xFF\xFF\xFF
I Am Listening
On TCP 2512
Reproducing The Vulnerability
ntdll!
A Crash
RtlAllocateHeap
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 Finish
: bp WSARecv and send overflow again
WSARecv
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
Jump If Our Packet
Specified A Size Larger
Than 0x408
Load First DWORD Of
Packet Into EAX
Compare Against Size
Of Current Buffer
0x408
Understanding The Bug
Trace Through Code To Determine Paths
: Eventually get to here
EAX == ESI + 3C
ESI == First DWORD
From Packet
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
RTLAllocateHeap()
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
0x0a871cc8 – 0x0a871c60
= 0x68
0x0a871d00 – 0x0a871c98
= 0x68
Lookaside[8] Has A Top Chunk That Sits
After Lookaside[7] Top Chunk On All Runs
AND
The Difference Is Greater Than 0x3C
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
Overwrite The Pointer Table
: 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
Heap/Stack Flip Local To
Citrix DLLS
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