HEAPS ABOUT HEAPS This Talk Covers Windows 2003
HEAPS ABOUT HEAPS
This Talk Covers Windows 2003 : Windows 2003 SP 2 : 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 BHUS 08 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 Heap. Set. Information() : Heap. Enable. Terminate. On. Corruption() : Windows Vista and Windows Server 2008 Need To Get Creative In Exploitation Methods
A Heap In Motion Initial 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 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 Last Free Chunk Header Chunk A Space Chunk B Header Free Chunk Header Chunk B Space 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
The Heap In Motion Initial Heap Allocated A, B, C Free B Free A Heap Management Last Free Chunk Header Chunk A Header Free Chunk Header Chunk A Space Free Chunk Space Chunk B Header Free Chunk Header Chunk B Space Free Chunk Space Chunk C Header Last Free Chunk Space Free chunks. Chunk that sit next to Chunk C Space each other are joined together. Last Free Chunk(Coalesced) Last Free Chunk C Header Chunk C Space Header Last Free Chunk Space Last Free Chunk Space
Heap Management Structure Heap Management Address These Flagsare hold settings All offsets from the such Exception baseasofis. Debug, the Heap Object The maximum size of an Raising, and Executable allocation before a Virtual Heap Linked list of blocksis Memory allocation Aallocated four DWORD from bitmask Virtual performed with each setchunk if the in Pointer to. Memory thebitfirst corresponding Free. List[n] is Free. List[0] is used to store Start of populated double linked lists Pointer to Free Critical. Section 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 expanded and more pages allocator. Flag that stores settings This iscommitted aof to the Pointer Start topointer the 48 Last byte Free about. Lookaside the front end Lookaside Chunk inlist theheaders heap allocator Value 00360000 Description Base Address 0036000 C 00000002 Flags 00360010 0000 Force. Flags 00360014 0000 FE 00 Virtual. Memory. Threshold 00360050 Virtual. Allocated. Blocks List 00360158 0000 Free. List Bitmap 00360178 00361 E 90 Free. List[0] 00360180 Free. List[n] 00360578 00360608 Heap. Lock. Section 0036057 C 0000 Commit Routine Ptr 00360580 00360688 Front. End. Heap 00360586 00000001 Front. End. Heap. Type 00360678 00361 E 88 Last Free Chunk 00360688 0000 Lookaside[n]
Heap Management Structure - Virtual Memory Allocation Heap Management EBX is set to Base Address Check threshold Address Value Description 00360014 0000 FE 00 Virtual. Memory. Threshold 00360050 Virtual. Allocated. Blocks List 7 C 82 AE 14 CMP EDI, DWORD PTR DS: [EBX+14] 7 C 82 AE 17 JBE ntdll. 7 C 82 A 2 FC. . . 7 C 82 AE 8 E LEA EAX, DWORD PTR DS: [EBX+50]. . . 7 C 82 AE 97 MOV EDX, DWORD PTR DS: [EAX+4]. . . 7 C 82 AEA 0 MOV DWORD PTR DS: [ECX], EAX 7 C 82 AEA 2 MOV DWORD PTR DS: [ECX+4], EDX 7 C 82 AEA 5 MOV DWORD PTR DS: [EDX], ECX 7 C 82 AEA 7 MOV DWORD PTR DS: [EAX+4], ECX 00360050 FLINK 00360054 BLINK Load BLINK ECX is @New. Chunk Write @New. Chunk to @BLINK+4 If the Virtual. Allocated. Blocks->BLINK can be overwritten the address of the New. Chunk can be written to an arbitrary location
Heap Management Structure - Free. List Bitmap Heap Management Bitmap is populated when chunk added to Free. List[n] 80 00 0 -7 00 02 00 24 -31 00 80 00 Address Value 00360158 0000 00 48 -55 7 C 82 A 291 LEA ESI, DWORD PTR DS: [EBX+EDX*4+158]. . . 7 C 82 A 2 A 8 AND EAX, DWORD PTR DS: [ESI]. . . 7 C 82 A 2 B 8 JNZ ntdll. 7 C 82 CB 46 7 C 82 A 2 BE TEST EAX, EAX 7 C 82 A 2 C 0 JNZ ntdll. 7 C 82 C 8 C 9 7 C 82 A 2 C 6 MOV EAX, DWORD PTR DS: [ESI] 00 Description Free. List Bitmap 00 00 Bitmap is checked when looking for a Free. List[n] that fits the request If a match is found then the corresponding Free. List[n] is used for the allocation. If the Bitmap can be manipulated then a pointer to an empty Free. List[n] can be returned, allowing the overwrite of management structures. [nico]
Heap Management Structure - Free. List Bitmap Heap Management Free. List[7] is populated 80 00 00 01 02 00 00 80 Free. List[16] is Modify bitmap empty 00 Address Value 00360158 0000 00 00 Description Free. List Bitmap 00 00 Free. Lists Address Value Description 003601 B 0 00364 D 78 Free. List[7] Request for block 16 will create a new block and return 003601 F 8 return it . . . 003601 F 8 . . . XXXX 003601 F 8 Overwrite Free. List[16] XXXXXXXX Overwrite If the Bitmap can be manipulated then a pointer to an empty Free. List[n] can be returned, allowing the overwrite of management structures. [nico]
Heap Management Structure - Free. List Bitmap Part Of The Bitmap Loading Code 7 C 82 C 8 AB MOVZX EAX, AH 7 C 82 C 8 AE MOVSX EAX, BYTE PTR DS: [EAX+7 C 82 BAB 8] 7 C 82 C 8 B 5 ADD EAX, 8 7 C 82 C 8 B 8 JMP ntdll. 7 C 82 C 830 7 C 82 C 8 BD MOVSX EAX, BYTE PTR DS: [ECX+7 C 82 BAB 8] 7 C 82 C 8 C 4 JMP ntdll. 7 C 82 C 830 7 C 82 C 8 C 9 LEA EDX, DWORD PTR DS: [EBX+178] 7 C 82 C 8 CF JMP ntdll. 7 C 82 C 808 7 C 82 C 8 D 4 SHR EAX, 18 7 C 82 C 8 D 7 MOVSX EAX, BYTE PTR DS: [EAX+7 C 82 BAB 8] 7 C 82 C 8 DE ADD EAX, 18 7 C 82 C 8 E 1 JMP ntdll. 7 C 82 C 830 [ 7 C 82 BAB 8 ] 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 Free. List[n] can be returned, allowing the overwrite of management structures. [nico]
Heap Management Structure – Free. List[n] Heap Management Free. List[0] is similar to Free. List[n] but holds chunks > 1016 bytes Address Value Description 00360178 00361 e 90 Free. List[0] 00360180 Free. List[n] 00360180 FLINK 00360184 BLINK Free Chunk Header Links Self Size Prev Size CK FLINK FL UN SI BLINK Free Chunk 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 0036057 C 0000 Commit Routine Ptr Initially set to nothing 7 C 833 BF 9 MOV ECX, DWORD PTR DS: [EAX+57 C] 7 C 833 BFF TEST ECX, ECX 7 C 833 C 01 JNZ ntdll. 7 C 852 C 9 E. . . 7 C 852 C 9 E PUSH EBX 7 C 852 C 9 F LEA EDX, DWORD PTR SS: [EBP+14] 7 C 852 CA 2 PUSH EDX 7 C 852 CA 3 PUSH EAX 7 C 852 CA 4 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 +08 +0 C +10. . . Allocation tracking for automatic Lookaside Fine Tuning Address Value Description 00360688 0000 003606 E 8 Lookaside[n] Lookaside[2] 48 byte structure Lookaside Chunk Header Links Self Size Prev Size CK FL UN SI FLINK Lookaside Chunk 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 Free. List 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 FFU 1 40 FFU 2 80 No Coalesce
Lookaside Lists Lookaside Starts Empty Lookaside[n]->FLINK Chunk Removed Added From Tois Top corrupted Of. Of Lookaside[n] FLINK 003620 D 0 XXXX 0000 00362100 003620 E 8 Address FLINK 003620 D 0 00362100 003620 E 8 003620 D 0 XXXX 0000 003620 E 8 Address This Value Gets Copied To Here Copied FLINK 003620 D 0 003620 E 8 003620 D 0 0000 About Overwrite To Allocate the FLINK From of the The Lookaside[n] top chunk Address FLINK 003620 D 0 0000 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 Freelist[n] Lookaside[n] Address FLINK 003620 D 0 0000 00362100 003620 E 8 BLINK 00360190 00362130 00360190 00362160 Chunk Added To Bottom Chunk Added Removed To From Bottom Address FLINK BLINK 00362130 00360190 00362160 00360190 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 Size Is Overwritten FLINK / BLINK Can Be Overwritten Chunk On Free. List Header #### Links Prev Size FLINK CK FL UN SI BLINK Data 7 C 82 C 8 E 6 MOVZX ECX, WORD PTR DS: [ESI] ; Load Self Size 7 C 82 C 8 E 9 MOV EDX, ECX. . 7 C 82 C 902 8 DBC 1 A 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]/Free. List[n] Size Is Overwritten Cookie Is Left Intact Freeing To Lookaside[n] Freelist[n] Chunk To Be Freed Header #### Prev Size CK FL UN SI Data 7 C 82 A 84 C MOVZX 7 C 829 F 1 B MOVZX EAX, WORD PTR DS: [ESI] SS: [EBP-20] ; Load selfsize self size 7 C 829 F 1 E MOV 7 C 82 A 850 LEA EBX, DWORD PTRPTR SS: [EBP-20], EAX DS: [EDI+EAX*8+178] ; Calculate 7 C 829 F 21 CMP 7 C 82 A 857 MOVEAX, 80 DWORD PTR SS: [EBP-88], EBX 7 C 829 F 26 JNB 7 C 82 A 85 D CMPntdll. 7 C 82 A 7 BC DWORD PTR DS: [EBX], EBX ; Check Freelist 7 C 829 F 2 C PUSH DWORD PTR SS: [EBP+10] 7 C 829 F 2 F LEA EAX, DWORD PTR DS: [EAX+EAX*2] ; Calculate Lookaside 7 C 829 F 32 SHL EAX, 4 Coalescing Is A Problem That Needs To Be Dealt With 7 C 829 F 35 ADD EAX, ECX 7 C 829 F 37 PUSH EAX 7 C 829 F 38 CALL ntdll. 7 C 829 F 8 F ; Push to Lookaside Could This Be Useful When Filling In Gaps?
Free. List[0] - Freelist[0] Address FLINK BLINK 00360178 00361 E 90 00362 B 60 Populated Freelist[0] Address FLINK BLINK 00361 E 90 003622 D 0 00360178 Address FLINK BLINK 003622 D 0 00362 B 60 00361 E 90 Address FLINK BLINK Load Freelist[0]->FLINK Check Size Is Larger Than Not Greater, Load Chunk Been Free’d ->FLINK Check Size Is Great Than If. Chunk It Is Greater Then Been Free’d Insert Chunk 00362 B 60 00360178 003622 D 0 Exploitable Condition On Freelist[0] Insert
Exploiting Free. List[0] - Free An Overwritten Chunk In Freelist[0] Can Be Exploited To Write The Address Of The Chunk Being Freed To An Arbitrary Location 7 C 82 A 982 CMP DX, WORD PTR DS: [EAX] 7 C 82 A 985 JA ntdll. 7 C 82 FDC 4 ; Compare chunk size ; To large move to next 7 C 82 A 98 B LEA EAX, DWORD PTR DS: [ESI+8] 7 C 82 A 98 E MOV DWORD PTR SS: [EBP-7 C], EAX 7 C 82 A 991 MOV EDX, DWORD PTR DS: [ECX+4] 7 C 82 A 994 MOV DWORD PTR SS: [EBP-84], EDX 7 C 82 A 99 A MOV DWORD PTR DS: [EAX], ECX 7 C 82 A 99 C MOV DWORD PTR DS: [EAX+4], EDX 7 C 82 A 99 F MOV DWORD PTR DS: [EDX], EAX 7 C 82 A 9 A 1 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 Free. List[0] - Free Chunk Is Inserted Before The Overwritting Chunk. FLINK and BLINK updated Chunk To Be Freed @003622 D 0 8400 Prev Size 00361 E 90 CK FL FL UN UN 00360718 SI Overwritten Chunk @00361 E 90 FFFF ? ? 02 ? ? 003622 D 0 00360718 Place Where We Want To Write 003622 D 0 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 ? ?
Free. List[0] - Allocate Freelist[0] Address FLINK BLINK 00360178 00361 E 90 00362 B 60 Populated Freelist[0] Address FLINK BLINK 00361 E 90 003622 D 0 00360178 Address FLINK BLINK 003622 D 0 00362 B 60 00361 E 90 Address FLINK BLINK 00362 B 60 00360178 003622 D 0 Load Freelist[0]->BLINK Freelist[0]->FLINK Check Size Is Large Too. For Small, Enough Request Load Chunk->FLINK Check Size Is Large. For Enough, Enough Request Return Chunk Check Size Is Large Enough For Request Exploitable Condition On Freelist[0] Allocate
Exploiting Free. List[0] - Searching Overwritten Chunk @003622 C 8 Request Made For Size 0 x 0 BF 8 0100 ? ? 00360188 ? ? ? ? FLINK Points To Fake Chunk+8 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 Space New Chunk Header New Chunk Space Chunk Returned To Caller New Header Is Written Into The Existing Chunk Space Chunk Inserted Into Free. Lists
Exploiting Free. List[0] - Relinking Overwritten Chunk @003622 C 8 Request Made For Size Smaller Than Our Overwrite 0202 ? ? READ XXXXXXXXXXXXXXXXX. . . FLINK Points To Fake Chunk+8 Chunk Fake Chunk @00360574 7005 3600 ? ? ? ? > Relink Chunk Size ? ? 0036057 C Relink Chunk Address Written To 00360580 This Is The Front. End. Heap (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 7 C 82 A 3 DB CMP EBX, 1 7 C 82 A 3 DE JE ntdll. 7 C 82 E 5 A 4 7 C 82 A 3 E 4 MOV EAX, DWORD PTR SS: [EBP-48] 7 C 82 A 3 E 7 LEA EDI, DWORD PTR DS: [ESI+EAX*8]. . 7 C 82 A 3 F 3 MOV BYTE PTR DS: [EDI+5], CL 7 C 82 A 3 F 6 MOV WORD PTR DS: [EDI+2], AX. . 7 C 82 A 400 MOV WORD PTR DS: [EDI], BX 7 C 82 A 403 TEST CL, 10 7 C 82 A 406 JNZ ntdll. 7 C 82 A 65 E 7 C 82 A 40 C LEA EAX, DWORD PTR DS: [EDI+EBX*8] 7 C 82 A 40 F 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 7 C 82 A 6 F 6 JE SHORT ntdll. 7 C 82 A 702 7 C 82 A 6 F 8 TEST BYTE PTR DS: [ESI+5], 1 7 C 82 A 6 FC JE ntdll. 7 C 82 CA 7 A 7 C 82 A 702 TEST BYTE PTR DS: [EDI+5], 10 7 C 82 A 706 JNZ ntdll. 7 C 82 A 7 B 3 7 C 82 A 70 C MOV EAX, DWORD PTR SS: [EBP+10] 7 C 82 A 70 F MOV EAX, DWORD PTR DS: [EAX] 7 C 82 A 711 LEA ESI, DWORD PTR DS: [EDI+EAX*8] 7 C 82 A 714 TEST BYTE PTR DS: [ESI+5], 1 7 C 82 A 718 JNZ ntdll. 7 C 82 A 7 B 3 Test Flag Of Previous Chunk ; 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 ; 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 > 0 x. FE 00 : 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 ? ? ? ? ? ? 01 FF FF FF DATA BUSY Chunk FFFF BUSY Chunk A Will Be Free’d And We Want To Prevent Coalescing FFFF FF DATA Chunk A Data Stored In Chunk B We Overflowing Keep The Flag Set To BUSY
Coalesced Chunks ? ? ? ? ? ? 01 FF FF FF 01 FF FF DATA BUSY Chunk FFFF FF Chunk A Data Stored In DATA 0200 FFFF BUSY Chunk 0200 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 ? ? ? ? ? ? 10 FF FF FF DATA BUSY Chunk FFFF BUSY Chunk B Will Be Free’d And We Want To Prevent Coalescing 0000 FFFF FF DATA Chunk A Data Stored In 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 0300 06 01 0 E 00 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 0 x 0000 Before Allocation Overwrite Flag And FLINK Self Size Prev Size CK FL UN SI 0300 06 01 0 E 00 0101 01 02 01 01 00362100 0000 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 EBP -> DATA ECX -> DATA EAX-> DATA PUSH EBX POP ESP POP EBP RET LEAVE RET MOV ESP, ECX RET 8 XCHG EAX, ESP 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 Heap. Create() : 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 Set. Process. DEPPolicy() : Not available on 2003 Copy Shellcode To RWE Memory Page : Copy shellcode and then return to address Virtual. Protect() : Use the PAGE_EXECUTE_READWRITE flag to reset heap : Return to shellcode
Bypassing DEP Virtual. Alloc() : Allocate new memory with PAGE_EXECUTE_READWRITE : Address is returned in EAX : Copy shellcode and return to it Nt. Set. Information. Process() : Skape and Skywing ret-to-libc to deactivate DEP : Easier on windows 2003 Nt. Set. Information. Process( Nt. Current. Process(), // (HANDLE)-1 Process. Execute. Flags, // 0 x 22 &Execute. Flags, // ptr to 0 x 2 sizeof(Execute. Flags)); // 0 x 4
Bypassing DEP Perfect Instruction Set BUT! Requires [ESI+37] To Be Writable Correctly Set Stack Nt. Set. Information. Process( Nt. Current. Process(), // (HANDLE)-1 Process. Execute. Flags, // 0 x 22 &Execute. Flags, // ptr to 0 x 2 sizeof(Execute. Flags)); // 0 x 4
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 Ima. Srv. 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 Ima. Srv. 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 0 x. FF send to TCP 2512 } x. FFx. FF I Am Listening On TCP 2512
Reproducing The Vulnerability ntdll! A Crash Rtl. Allocate. Heap 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 Load First DWORD Of Packet Into EAX Compare Against Size Of Current Buffer 0 x 408 Jump If Our Packet Specified A Size Larger Than 0 x 408
Understanding The Bug Trace Through Code To Determine Paths : Eventually get to here EAX == ESI + 3 C 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!RTLAllocate. Heap Allocate From Heap 00320000 Allocate 3 B 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 0 x 3 C Bytes Long
Understanding The Bug Finally. . : A memmove instruction overflows the buffer New Buffer+3 C 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 0 x 01 – 0 x 03 B : We can overflow the chunk with 0 x 408 bytes The Limitations : Can only allocate chunk 2 through to 9 That range is FFFFFFC 5 == 0 x 01 == Chunk 2 To FFFF == 0 x 3 b == Chunk 9 : The first 0 x 3 C bytes are not controlled by us due to the custom header
The Request Life. Cycle RTLAllocate. Heap() WSARecv() memmove() RTLFree. Heap() 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 0 x 0 a 871 c 38 – 0 x 0 a 871 bd 0 = 0 x 68 0 x 0 a 871 cc 8 – 0 x 0 a 871 c 60 = 0 x 68 0 x 0 a 871 d 00 – 0 x 0 a 871 c 98 = 0 x 68 Lookaside[8] Has A Top Chunk That Sits After Lookaside[7] Top Chunk On All Runs AND The Difference Is Greater Than 0 x 3 C
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 0 x 71 C 14044 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 : 0 x 142360 Set Lookaside Address : Need to account for header : Set lookaside to 0 x 01431 D 0 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 0 ded Shok Sotirov Sandip Chaudhari A. Anisimov N. Falliere Halvar Litchfield + All Others
- Slides: 66