You are on page 1of 66

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

You might also like