Upload
horace-lambert
View
215
Download
0
Tags:
Embed Size (px)
Citation preview
UT HEAPSHEAPS ABO
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
This Talk Covers
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
Windows Heap
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
Heap Exploit Difficulties
Need To Get Creative In Exploitation Methods
Initial Heap
Heap Management
Last Free Chunk Header
Last Free Chunk Space
A Heap In Motion
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.
Initial Heap
Heap Management
Last Free Chunk Header
Last Free Chunk Space
The Heap In Motion
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 Chunk Header
Last Free Chunk Space
After the allocation of three memory chunks, the heap layout now looks like this
Initial Heap
Heap Management
Last Free Chunk Header
Last Free Chunk Space
The Heap In Motion
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 Chunk Header
Last Free Chunk Space
Free B
Heap Management
Chunk A Header
Chunk A Space
Free Chunk Header
Free Chunk Space
Chunk C Header
Chunk C Space
Last Free Chunk Header
Last Free Chunk Space
Freeing a chunk in
between two busy chunks,
creates a Free Chunk
Initial Heap
Heap Management
Last Free Chunk Header
Last Free Chunk Space
The Heap In Motion
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 Chunk Header
Last Free Chunk Space
Free B
Heap Management
Chunk A Header
Chunk A Space
Free Chunk Header
Free Chunk Space
Chunk C Header
Chunk C Space
Last Free Chunk Header
Last Free Chunk Space
Free A
Heap Management
Free Chunk Header
Free Chunk Space
Chunk C Header
Chunk C Space
Last Free Chunk Header
Last Free Chunk Space
Free chunks that sit next to each other are joined (Coalesced) together.
Heap Management StructureHeap Management
Address Value Description
00360000 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]
All offsets are from the base of the Heap ObjectThese Flags hold settings
such as isDebug, Exception Raising, and Executable
Heap
The maximum size of an allocation before a Virtual
Memory allocation is performed
Linked list of blocks allocated from Virtual
MemoryA four DWORD bitmask with each bit set if the
corresponding FreeList[n] is populated
Pointer to the first chunk in FreeList[0]
FreeList[0] is used to store Free Chunks > 1016 bytesStart of double linked lists
to store Free ChunksPointer to CriticalSection that is used to lock the heap during changes
Pointer to Function() that is called when the heap is
expanded and more pages committed
Pointer to the front end allocator.
This is a pointer to the Lookaside
Flag that stores settings about the front end
allocator
Pointer to the Last Free Chunk in the heap
Start of the 48 byte Lookaside list headers
Heap Management Structure - Virtual Memory AllocationHeap Management
Address Value Description
00360014 0000FE00 VirtualMemoryThreshold
00360050 00360050 VirtualAllocatedBlocks List
00360050 FLINK
00360054 BLINK7C82AE14 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],EAX7C82AEA2 MOV DWORD PTR DS:[ECX+4],EDX7C82AEA5 MOV DWORD PTR DS:[EDX],ECX7C82AEA7 MOV DWORD PTR DS:[EAX+4],ECX
EBX is set to Base AddressCheck threshold
Load BLINK
Write @NewChunk to @BLINK+4
ECX is @NewChunk
If the VirtualAllocatedBlocks->BLINK can be overwritten then the address of the NewChunk can be written to an arbitrary location
Heap Management Structure - FreeList BitmapHeap Management
Address Value Description
00360158 00000000 FreeList Bitmap
7C82A291 LEA ESI,DWORD PTR DS:[EBX+EDX*4+158]...7C82A2A8 AND EAX,DWORD PTR DS:[ESI]...7C82A2B8 JNZ ntdll.7C82CB467C82A2BE TEST EAX,EAX7C82A2C0 JNZ ntdll.7C82C8C97C82A2C6 MOV EAX,DWORD PTR DS:[ESI]
Bitmap is checked when looking for a FreeList[n]
that fits the request
Bitmap is populated when chunk added to FreeList[n]
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]
80 00 00 02 00 00 80 00 00 00 00 00 00 00 00 00
0-7 24-31 48-55
Heap Management Structure - FreeList BitmapHeap Management
Address Value Description
00360158 00000000 FreeList Bitmap
If the Bitmap can be manipulated then a pointer to an empty FreeList[n] can be returned, allowing the overwrite of management structures. [nico]
80 00 00 02 00 00 80 00 00 00 00 00 00 00 00 00
FreeList[7] is populated
FreeList[16] is empty
FreeLists
Address Value Description
003601B0 00364D78 FreeList[7]
... ... ...
003601F8 003601F8 FreeList[16]Request for block 16 will create a new block and
return it
Modify bitmap
Request for block 16 will return 003601F8
80 00 01 02 00 00 80 00 00 00 00 00 00 00 00 00
FreeLists
Address Value Description
003601B0 00364D78 FreeList[7]
... ... ...
003601F8 XXXXXXXX Overwrite
XXXXXXXX Overwrite
XXXXXXXX Overwrite
XXXXXXXX Overwrite
XXXXXXXX Overwrite
Heap Management Structure - FreeList Bitmap
If the Bitmap can be manipulated then a pointer to an empty FreeList[n] can be returned, allowing the overwrite of management structures. [nico]
Part Of The Bitmap Loading Code
7C82C8AB MOVZX EAX,AH7C82C8AE MOVSX EAX,BYTE PTR DS:[EAX+7C82BAB8]7C82C8B5 ADD EAX,87C82C8B8 JMP ntdll.7C82C8307C82C8BD MOVSX EAX,BYTE PTR DS:[ECX+7C82BAB8]7C82C8C4 JMP ntdll.7C82C8307C82C8C9 LEA EDX,DWORD PTR DS:[EBX+178]7C82C8CF JMP ntdll.7C82C8087C82C8D4 SHR EAX,187C82C8D7 MOVSX EAX,BYTE PTR DS:[EAX+7C82BAB8]7C82C8DE ADD EAX,187C82C8E1 JMP ntdll.7C82C830
[ 7C82BAB8 ]A Static Pointer To A Bit Mask Table That Can Be Modified To Manipulate
The Bitmap Result
Heap Management Structure – FreeList[n]Heap Management
Address Value Description
00360178 00361e90 FreeList[0]
00360180 00360180 FreeList[n]
FreeList[0] is similar to FreeList[n] but holds chunks > 1016 bytes
00360180 FLINK
00360184 BLINK
Free Chunk Header
Header Self Size Prev Size CK FL UN SI
Links FLINK BLINK
Free Chunk Header
Header Self Size Prev Size CK FL UN SI
Links FLINK BLINK
Double Linked List connects free
chunks together
Heap Management Structure - Commit Routine PointerHeap Management
Address Value Description
0036057C 00000000 Commit Routine Ptr
7C833BF9 MOV ECX,DWORD PTR DS:[EAX+57C]7C833BFF TEST ECX,ECX7C833C01 JNZ ntdll.7C852C9E...7C852C9E PUSH EBX7C852C9F LEA EDX,DWORD PTR SS:[EBP+14]7C852CA2 PUSH EDX7C852CA3 PUSH EAX7C852CA4 CALL ECX
Initially set to nothing
Custom function() called when committing more
memory to the Heap
This is a static pointer that can be overwritten to gain execution control
Loaded into ECX and called
Heap Management Structure – Lookaside[n]Heap Management
Address Value Description
00360688 00000000 Lookaside[n]
003606E8 Lookaside[2]
Lookaside[0] and Lookaside[1] are not used
48 byte structureLookaside List Header
Address Description
+00 Pointer To First Chunk
+04 Depth
+06 Max Depth
+08Allocation tracking for automatic Lookaside
Fine Tuning
+0C
+10
...
Lookaside Chunk Header
Header Self Size Prev Size CK FL UN SI
Links FLINK
Lookaside Chunk Header
Header Self Size Prev Size CK FL UN SI
Links FLINK
Heap Chunks
Chunk On Lookaside
Header Self Size Prev Size CK FL UN SI
Links FLINK
Data
A Used Chunk
Header Self Size Prev Size CK FL UN SI
Data
Chunk On FreeList
Header Self Size Prev Size CK FL UN SI
Links FLINK BLINK
Data
Chunk Flags
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[n]
FLINK 00000000
Lookaside Starts Empty
Address FLINK
003620D0 00000000
Lookaside[n]
FLINK 003620D0
Chunk Added To Top Of Lookaside
Address FLINK
003620E8 003620D0
Lookaside[n]
FLINK 003620E8
Chunk Added To Top Of Lookaside
Address FLINK
003620D0 00000000
Address FLINK
00362100 003620E8
Lookaside[n]
FLINK 00362100
Chunk Added To Top Of Lookaside
Address FLINK
003620E8 003620D0
Address FLINK
003620D0 00000000
About To Allocate From The Lookaside[n]
This Value Gets Copied
Address FLINK
00362100 003620E8
Lookaside[n]
FLINK 00362100
Address FLINK
003620E8 003620D0
Address FLINK
003620D0 00000000
Chunk Removed From Top Of Lookaside
Lookaside[n]
FLINK 003620E8
Address FLINK
003620E8 003620D0
Address FLINK
003620D0 00000000
Copied To Here
There is no Safe Unlinking or Cookie check for Lookaside ListsWell 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.
Overwrite the FLINK of the top chunk
Lookaside[n]
FLINK 003620E8
Address FLINK
003620E8 XXXXXXXX
Address FLINK
003620D0 00000000
Lookaside[n]->FLINK is corrupted
Lookaside[n]
FLINK XXXXXXXX
Freelist[n] Lists
Lookaside[n]
FLINK 00000000
Freelist Starts Empty
Lookaside[n]
FLINK 003620D0
Lookaside[n]
FLINK 003620E8
Lookaside[n]
FLINK 00362100
Lookaside[n]
FLINK 00362100
Lookaside[n]
FLINK 003620E8
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
Lookaside[n]
FLINK 003620E8
Freelist[n]
Address FLINK BLINK
00360190 00360190 00360190
Address FLINK BLINK
00362130 00360190 00360190
Chunk Added To Bottom
Freelist[n]
Address FLINK BLINK
00360190 00362130 00362130
Address FLINK BLINK
00362160 00360190 00362130
Chunk Added To Bottom
Freelist[n]
Address FLINK BLINK
00360190 00362130 00362160
Address FLINK BLINK
00362130 00362160 00360190Chunk Removed
From Bottom
Freelist[n]
Address FLINK BLINK
00360190 00362130 00362130
Address FLINK BLINK
00362130 00360190 00360190
Freelist Is Empty
Freelist[n] Lists
Freelist Searching: If a freelist[n] of requested size not availablebitmap 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
Size Is OverwrittenFLINK / BLINK Can Be
Overwritten
7C82C8E6 MOVZX ECX,WORD PTR DS:[ESI] ; Load Self Size7C82C8E9 MOV EDX,ECX..7C82C902 8DBC1A 58010000 LEA EDI,DWORD PTR DS:[EDX+EBX+158]
Calculate Bitmap
Bitmap Attack Explained Earlier
Chunk On FreeList
Header #### Prev Size CK FL UN SI
Links FLINK BLINK
Data
If Last Chunk On Freelist Then Bitmap Updated
If FLINK and BLINK Overwritten with Valid For Read and
FLINK == BLINKThen Bitmap Updated
Free To Arbitrary Lookaside[n]/FreeList[n]
Size Is OverwrittenCookie Is Left Intact
Chunk To Be Freed
Header #### Prev Size CK FL UN SI
Data
7C829F1B MOVZX EAX,WORD PTR DS:[ESI] ; Load self size7C829F1E MOV DWORD PTR SS:[EBP-20],EAX7C829F21 CMP EAX,807C829F26 JNB ntdll.7C82A7BC7C829F2C PUSH DWORD PTR SS:[EBP+10]7C829F2F LEA EAX,DWORD PTR DS:[EAX+EAX*2] ; Calculate Lookaside7C829F32 SHL EAX,47C829F35 ADD EAX,ECX7C829F37 PUSH EAX7C829F38 CALL ntdll.7C829F8F ; Push to Lookaside
Freeing To Lookaside[n]
Could This Be Useful When Filling In Gaps?
7C82A84C MOVZX EAX,WORD PTR SS:[EBP-20] ; Load selfsize7C82A850 LEA EBX,DWORD PTR DS:[EDI+EAX*8+178] ; Calculate 7C82A857 MOV DWORD PTR SS:[EBP-88],EBX7C82A85D CMP DWORD PTR DS:[EBX],EBX ; Check FreelistFreeing To
Freelist[n]
Coalescing Is A Problem That Needs To Be Dealt With
FreeList[0] - Free
Address FLINK BLINK
00361E90 003622D0 00360178
Freelist[0]
Address FLINK BLINK
00360178 00361E90 00362B60
Address FLINK BLINK
003622D0 00362B60 00361E90
Address FLINK BLINK
00362B60 00360178 003622D0
Populated Freelist[0]
Load Freelist[0]->FLINK
Check Size Is Larger Than Chunk Been Free’dNot Greater, Load
Chunk->FLINK
Check Size Is Great Than Chunk Been Free’dIf It Is Greater Then
Insert Chunk
Exploitable Condition On Freelist[0] Insert
Exploiting FreeList[0] - Free
Exploitable Condition On Freelist[0] Insert
7C82A982 CMP DX,WORD PTR DS:[EAX] ; Compare chunk size7C82A985 JA ntdll.7C82FDC4 ; To large move to next
7C82A98B LEA EAX,DWORD PTR DS:[ESI+8] ; Header of free’d chunk7C82A98E MOV DWORD PTR SS:[EBP-7C],EAX7C82A991 MOV EDX,DWORD PTR DS:[ECX+4] ; Load BLINK of current chunk7C82A994 MOV DWORD PTR SS:[EBP-84],EDX7C82A99A MOV DWORD PTR DS:[EAX],ECX ; Set free’d->FLINK == current7C82A99C MOV DWORD PTR DS:[EAX+4],EDX ; Set free’d->BLINK ==current->BLINK7C82A99F MOV DWORD PTR DS:[EDX],EAX ; Write @free’d to [current->BLINK]7C82A9A1 MOV DWORD PTR DS:[ECX+4],EAX ; Set current->BLINK == @free’d
An Overwritten Chunk In Freelist[0] Can Be Exploited To Write The Address Of The Chunk Being Freed To An Arbitrary Location
Exploiting FreeList[0] - Free
Exploitable Condition On Freelist[0] Insert
Chunk To Be Freed @003622D0
8400 Prev Size CK FL UN SIOverwritten Chunk @00361E90
FFFF ???? ?? 02 ?? ??
FFFFFFFF 00360718
Place Where We Want To Write 003622D0Could Be A Function Table, This Is A Lookaside
Chunk To Be Freed @003622D0
8400 Prev Size CK FL UN SI
00361E90 00360718 Overwritten Chunk @00361E90
FFFF ???? ?? 02 ?? ??
FFFFFFFF 003622D0
Overwritten Lookaside Now PopulatedThree Requests And We Get Our Set Location
Chunk Is Inserted Before The Overwritting Chunk.
FLINK and BLINK updated
FreeList[0] - Allocate
Address FLINK BLINK
00361E90 003622D0 00360178
Freelist[0]
Address FLINK BLINK
00360178 00361E90 00362B60
Address FLINK BLINK
003622D0 00362B60 00361E90
Address FLINK BLINK
00362B60 00360178 003622D0
Populated Freelist[0]
Load Freelist[0]->BLINK
Check Size Is Large Enough For Request
Load Freelist[0]->FLINK
Check Size Is Large Enough For RequestToo Small, Load Chunk->FLINK
Check Size Is Large Enough For RequestLarge Enough,
Return Chunk
Exploitable Condition On Freelist[0] Allocate
Exploiting FreeList[0] - Searching
Exploitable Condition On Freelist[0] Allocate - Searching
Overwritten Chunk @003622C8
0100 ???? ?? ?? ?? ??
00360188 ????????
Fake Chunk @00360180
8001 3600 80 01 36 00
00360188 00360188
Must Be ReadableMust Be Readable= Requested Size
(+1 block)
Request Made For Size0x0BF8
FLINK Points To Fake Chunk
FLINK Points To Fake Chunk+8
Chunk Returned To CallerThis Address Is In The
Freelists
Allocation Relinking
If Chunk Is Larger Than Request It Will Get Split
Chunk Header
Chunk Space
Chunk Header
Chunk Space
New Chunk Header
New Chunk Space
New Header Is Written Into The Existing Chunk
Space
Chunk Header
Chunk Space
New Chunk Header
New Chunk SpaceChunk Returned To
Caller
Chunk Inserted Into FreeLists
Exploiting FreeList[0] - Relinking
Exploitable Condition On Freelist[0] Allocate - Relinking
Overwritten Chunk @003622C8
0202 ???? ?? ?? ?? ??
0036057C READ
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.....
Request Made For SizeSmaller Than Our Overwrite
Fake Chunk @00360574
7005 3600 08 06 36 00
???????? 00360688
Must Be Read/Write> Relink Chunk Size
FLINK Points To Fake Chunk
FLINK Points To Fake Chunk+8Relink Chunk Address
Written To 00360580
This Is The FrontEndHeap(Lookaside Base)
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
Splitting / Resizing
7C82A3DB CMP EBX,1 ; Larger than one block difference7C82A3DE JE ntdll.7C82E5A47C82A3E4 MOV EAX,DWORD PTR SS:[EBP-48] ; Load requested size7C82A3E7 LEA EDI,DWORD PTR DS:[ESI+EAX*8] ; Move to create the new chunk..7C82A3F3 MOV BYTE PTR DS:[EDI+5],CL ; Store new flag7C82A3F6 MOV WORD PTR DS:[EDI+2],AX ; Store Prev Size..7C82A400 MOV WORD PTR DS:[EDI],BX ; Store new size7C82A403 TEST CL,10 ; Is chunk new LAST CHUNK7C82A406 JNZ ntdll.7C82A65E ; Jump if chunk is last chunk7C82A40C LEA EAX,DWORD PTR DS:[EDI+EBX*8] ; Move to NEXT chunk based on size7C82A40F MOV DWORD PTR SS:[EBP-50],EAX ; Will try and coalesce with next
Can Skip By Setting As Last Chunk
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
: An overflow can control all of this to prevent coalesce
Coalesced Chunks
7C82A6F6 JE SHORT ntdll.7C82A702 ; If prev size is 0 jump7C82A6F8 TEST BYTE PTR DS:[ESI+5],1 ; Is prev chunk BUSY?7C82A6FC JE ntdll.7C82CA7A ; If not then coalesce7C82A702 TEST BYTE PTR DS:[EDI+5],10 ; Is our chunk the last chunk?7C82A706 JNZ ntdll.7C82A7B3 ; If so can't coalesce7C82A70C MOV EAX,DWORD PTR SS:[EBP+10]7C82A70F MOV EAX,DWORD PTR DS:[EAX] ; Load our block size7C82A711 LEA ESI,DWORD PTR DS:[EDI+EAX*8] ; Move to next chunk7C82A714 TEST BYTE PTR DS:[ESI+5],1 ; Is next chunk BUSY?7C82A718 JNZ ntdll.7C82A7B3 ; Yup, so don't colaesce
Test Flag Of Previous
Chunk
Test Flag Of Next Chunk
Header Self Size Prev Size CK FL UN SI
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
Preventing Coalesce
Coalesced Chunks
???? ???? ?? ?? ?? ??
DATA
FFFF FFFF FF FF FF FF
DATA
Chunk AData Stored In
Chunk BWe Overflowing
BUSYChunk
BUSYChunk
Chunk A Will Be Free’d And We Want To
Prevent Coalescing
FFFF FFFF FF 01 FF FF
DATA
Keep The Flag Set To BUSY
Coalesced Chunks
???? ???? ?? ?? ?? ??
DATA
FFFF FFFF FF FF FF FF
DATA
Chunk AData Stored In
Chunk BWe Overflowing
BUSYChunk
BUSYChunk
Chunk B Will Be Free’d And We Want To
Prevent Coalescing
FFFF FFFF FF 01 FF FF
DATA
0200 0200 FF FF FF FF
DATA
FFFF FFFF FF 01 FF FF
DATA
Create Two Fake Chunks And Set Size In Header Of Chunk B To Point To The Fake Chunks
Flag Set To Busy
Create Two Fake Chunks And Set Size In Header Of Chunk B To Point To The Fake Chunks
Flag Set To Busy
Coalesced Chunks
???? ???? ?? ?? ?? ??
DATA
FFFF FFFF FF FF FF FF
DATA
Chunk AData Stored In
Chunk BWe Overflowing
BUSYChunk
BUSYChunk
Chunk B Will Be Free’d And We Want To
Prevent Coalescing
FFFF 0000 FF 10 FF FF
DATA
Set The Flag To Contain The Last
Chunk Flag
How To Prevent A Free: Set the chunks flag to FAIL the BUSY check
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
Preventing A Free
Move To Chunk Header
Load Flag and Test If Busy
Example Removing Chunk From Lookaside
Before Allocation
After Free()
Overwrite Flag
Self Size Prev Size CK FL UN SI
0300 0300 06 01 0E 00
Self Size Prev Size CK FL UN SI
0101 0101 01 02 01 01
After Allocation
Top Chunk On A Lookaside Is Overwritten: Flags set to not BUSY, Flink set to 0x00000000
Clearing The Lookaside
Before Allocation
After Overwrite
Allocation And Free Will Clear The Lookaside List
Overwrite Flag And FLINK
Self Size Prev Size CK FL UN SI
0300 0300 06 01 0E 00
00362100
Self Size Prev Size CK FL UN SI
0101 0101 01 02 01 01
00000000
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?
The Exploitation Process
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
Heap / Stack Flipping
PUSH EBXPOP ESPPOP EBPRET
EBX -> DATA
LEAVERET
EBP -> DATA ECX -> DATA
MOV ESP,ECXRET 8
EAX-> DATA
XCHG EAX,ESPRET
Heap / Stack Flipping
Flipping Code
Stack
Exploit Data
Registers
Code Gets Executed
Heap / Stack Flipping
New Stack
Exploit Data
New RegistersCode That We Returned Into
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
Bypassing DEP
NtSetInformationProcess(NtCurrentProcess(), // (HANDLE)-1ProcessExecuteFlags, // 0x22&ExecuteFlags, // ptr to 0x2sizeof(ExecuteFlags)); // 0x4
Bypassing DEP
Perfect Instruction Set
NtSetInformationProcess(NtCurrentProcess(), // (HANDLE)-1ProcessExecuteFlags, // 0x22&ExecuteFlags, // ptr to 0x2sizeof(ExecuteFlags)); // 0x4
Requires [ESI+37] To Be Writable
Correctly Set Stack
BUT!
Step By Step: The vulnerability: Reproduction: Understanding the bug: Finding an overwrite: Find a pointer: Flipping the heap to stack: Bypassing DEP: The working
Heap Exploitation
The Vulnerability
CitrixImaSrv.exe
TCP Port 2512 or 2513User-supplied -> Memory Allocation
Undersized AllocationOverflow The Heap Buffer
Citrix
TCP Port 2512 or 2513 User-supplied -> Memory AllocationImaSrv.exe
Overflow The Heap Buffer
Usual Integer Overflow: Usual ‘packet size bug’
Usual Basic Fuzz Testwhile !crashed{
inc buffer lengthfill buffer with 0xFFsend to TCP 2512
}
Reproducing The Vulnerability
Length Of Data DATA
I Am Listening On TCP 2512
\xFF\xFF\xFF\xFF \xFF\xFF\xFF\xFF\xFF\xFF
Reproducing The Vulnerability
A CrashA Crashntdll! RtlAllocateHeap
In the good ‘ol days, it would now be as easy as overwriting the UEF. But those days are over.
Need To Trace From Start To Finish: bp WSARecv and send overflow again
Understanding The Bug
WSARecv
Stack
Buffer Size Buffer Address
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
Understanding The Bug
Load First DWORD Of Packet Into EAX
Compare Against Size Of Current Buffer
0x408Jump If Our Packet
Specified A Size Larger Than 0x408
Trace Through Code To Determine Paths: Eventually get to here
Understanding The Bug
ESI == First DWORD From Packet
EAX == ESI + 3CIs Going To
Allocate A Buffer Of Size EAX
EAX == ESI + 3C
But its not over yet: Trace down to ntdll!RTLAllocateHeap
Understanding The Bug
Allocate From Heap 00320000
Allocate 3B Bytes
Still Thats Just An Undersized Buffer: Keep tracing the code
Understanding The Bug
Bunch Of Stuff Is Written Into The New Buffer
This Is A Custom Header And Is 0x3C Bytes Long
EAX Points To The Newly Allocated Buffer
Finally....: A memmove instruction overflows the buffer
Understanding The Bug
New Buffer+3C
Packet Data
This Is The Size Of The Packet That We Sent
KABOOM!
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
Understanding The Bug
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 Request LifeCycle
WSARecv()
RTLFreeHeap()
RTLAllocateHeap()
memmove()
The Lookaside Lists
Lookaside[8] Has A Top Chunk That Sits After Lookaside[7] Top Chunk On All Runs
ANDThe Difference Is Greater Than 0x3C
0x0a871cc8 – 0x0a871c60= 0x680x0a871c38 – 0x0a871bd0
= 0x68
0x0a871d00 – 0x0a871c98= 0x68
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
Lets Try It
Function Pointer: Trace code looking for pointer: None found before WSARecv()
What Address To Overwrite
Lucky For Us That Winsock Uses Static Pointers
0x71C14044 Is A Static Pointer That Can Be Overwritten
EAX Points To Stack
Winsock: Holds a structure
: Structure holds pointer to function pointer table on the default heap
Winsock Structure
Static Pointer To Handle
Load Address Of Pointer Table
‘Static Within Heap’
Call Function
Pointer Table Address: 0x142360Set Lookaside Address: Need to account for header: Set lookaside to 0x01431D0Overwrite The Pointer Table: We now control executionSet The Stack: EAX points to the pointer table: EAX points to our data: Search for a heap/stack flipReturn Down The Stack: Return to Anti-DEP: Return to shellcode on pointer table
Exploiting The Bug
Heap/Stack Flip Local To Citrix DLLS
Da GreetzAcknowledgement 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
0dedShok
SotirovSandip Chaudhari
A. AnisimovN. Falliere
HalvarLitchfield
+ All Others