Heap overflow is related to the heap's memory layout, and to understand heap overflow, it is first to be clear what the heap memory layout of malloc () is, and what it will look like after the free () operation.
Solve the first problem: How to lay out the heap memory allocated through malloc ()?
Is the case where malloc () allocates two pieces of memory.
Where the mem pointer is to the address returned by malloc (), pre_size and size are 4 bytes of data, size holds the current chunk (memory block, not translated in this article), Pre_size stores the previous chunk size.
Because malloc realizes that the allocated memory space is 8-byte aligned, the low 3 bits of size are actually useless, taking one of them, to flag whether the previous chunk was released as Prev_inuse bit. Current one chunk released, prev_inuse position 0, otherwise set 1.
When the space allocated by malloc () is used, its mem pointer is passed to free () for release.
Solve the second question: What effect does free () have on the heap memory layout?
The situation is that the current chunk of the previous chunk was freed (), easy to find, the current chunk Prev_isuse flag position 0, indicating that the previous chunk has been released.
In the released chunk, the low address of the original data location is filled with two pointers, FD and BK, which are abbreviations for forward and backward words, respectively, representing the address of the previous free chunk and the last free chunk. Thus all memory chunk freed by free () will form a doubly linked list. Also therefore a chunk minimum length of 16 bytes: 2 size and 2 pointers.
When a chunk is released, there is another thing to do, is to check whether the adjacent chunk is released, if the adjacent chunk idle, it will be chunk merge operation. Because the size information is stored in each chunk, it is easy to find the status of chunk before and after the current chunk.
Free () calls a unlink macro to perform the merge operation:
#define unlink (P, BK, fd) { \ = p->fd; = p->bk; FD->BK = bk; BK->fd = fd; }
Well, this macro is the key to heap overflow utilization. Reading this macro is actually the operation of deleting a node in a doubly linked list:
P->FD->BK = p->bkP->bk->fd = p->fd
where p represents the node that is currently being deleted.
Solve the last question: How does a heap overflow work?
First construct a heap overflow vulnerability code:
int Main (void) { char *buff1, *buff2; malloc (a); malloc (a); Gets (BUFF1); Free (BUFF1); Exit (0);}
Give the heap space layout:
Low Address
+---------------------+ <--first chunk ptr
| Prev_size |
+---------------------+
| size=48 |
+---------------------+ <--first
| |
| Allocated |
| Chunk |
+---------------------+ <--second chunk ptr
| Prev_size |
+---------------------+
| size=48 |
+---------------------+ <--second
| Allocated |
| Chunk |
+---------------------+
High address
Now using the gets function for heap overflow, the 2nd block of Chunk Prev_size is overwritten with any value, size is covered by 4 that is, the 0XFFFFFFFC,FD location is overwritten by the [email PROTECTED],BK location is overwritten with the Shellcode address.
Post-overlay heap space layout conditions:
Low Address
+---------------------+ <--first chunk ptr
| Prev_size |
+---------------------+
| size=48 |
+---------------------+ <--first
| |
| Allocated |
| Chunk |
+---------------------+ <--second chunk ptr
| xxxxxxxxx |
+---------------------+
| size=0xfffffffc |
+---------------------+ <--second
| [email protected] | &NBSP
| shellcode address |
| Allocated |
| chunk |
+-------------------- -+&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP
high address
Here's what happens when Free (BUFF1):
1.first Space is buff1 released
2. Check if the previous chunk need to be merged (no here)
3. Check if the next chunk need to be merged, check the next chunk to check the PREV_ISUSE flag bit. That is, the current chunk plus the current size gets the next chunk, the next chunk plus the next size gets the next chunk, because we set the next chunk size to 4, then the chunk position of the next pre_size is considered the beginning of the next chunk, The next size position is the 0XFFFFFFFC flag that is not set and is considered free to be merged.
So, there's a problem with merging the unlink macros here, as well as in the picture above:
Second->fd->bk=second->BK /* 1.SECOND->BK is shellcode address 2. Shellcode's address was written in Second->fd+12 's location 3.SECOND->FD is the address of [email protected] -12 4. So the location of the second->fd+12 is [ Email protected] + = [email protected] is the exit address stored in got so the exit () function address has been replaced by the Shellcode address * / Second->BK->FD=SECOND->FD
"Shellcode address is written into the second->fd+12 position" This sentence to understand well, why SECOND->FD->BK is second->fd+12? In fact SECOND->FD refers to a forward chunk head, plus 12 is to skip pre_size,size and FD to reach BK position.
When the last program executes to the exit (0) statement, Shellcode executes because the address is replaced.
Analysis of Linux heap overflow principle