Exploitation of Linux heap overflow exploits unlink
Take a bit @ Ali Poly Security
0 Preface
Before we learned more about the operating mechanism of GLIBC malloc (see article link for the end ), Let's start with a real heap overflow exploit. To tell the truth, write this kind of article, I am more counseling, because I am currently engaged in the work with the loophole mining completely irrelevant, learning this part of the knowledge is purely a personal hobby, in the weekend bored to spend the next time, even my initial goal is only can quickly read, reproduce the various loopholes using POC just ... In view of this, the following articles will be roughly composed of two types of content: 1) A summary of various related articles, re-refining; 2) translation and extension of certain good articles. This article has both, the main references are shown here.
1 Background Introduction
First, there are the following procedures for vulnerabilities:
A heap overflow vulnerability exists in code [3]: If the size of the user input argv[1] is larger than the 666 bytes of the first variable, then the input data may be overwritten by a chunk chunk header--which can lead to arbitrary code execution. The core idea of attack is to utilize the unlink mechanism of glibc malloc.
The memory diagram for the above program is as follows:
2 Unlink Technical principle2.1 Introduction to basic knowledge
Unlink attack technology is the use of "glibc malloc" memory recycling mechanism, the second chunk to unlink off, and, in the process of unlink with the Shellcode address the free function (or other functions also line) got table entries. This way, when the program subsequently calls the free function (as in the code [5] above), it executes our shellcode. Clearly, the core is to understand the free mechanism of glibc malloc.
Under normal circumstances, the free execution process is described below:
PS: In view of the space, here is the main introduction of the non-mmaped chunks recovery mechanism, recall the circumstances under which the use of mmap allocation of new chunk, which cases do not mmap?
Once the free memory is involved, it means that there is a new chunk from the allocated state to the Free State, at which point glibc malloc needs to merge-forward and/or backward merge. The concept of forward backward is as follows: Merge previous free chunk into the current free chunk, called backward merge, and merge the following free chunk into the current free chunk, called forward merge.
One, back merge:
The relevant code is as follows:
First detects if the previous chunk is free, which can be detected by detecting the Prev_inuse (P) Bit of the currently available chunk. In this case, the previous chunk of the current chunk (first chunk) is allocated because, by default, the first chunk in heap memory is always set to allocated, even if it does not exist at all.
If it is free, then merge backwards:
1) Merge the memory occupied by the previous chunk into the current chunk;
2) Modify the pointer to the current chunk and point to the previous chunk instead.
3) Use the Unlink macro to remove the previous free chunk from the two-way loop list (it is best to draw your own understanding and learn the data structure should not be a problem).
In this case, because the previous chunk is allocated, the backward merge operation is not performed.
Second, forward merge operation:
First, check if the next chunk is free. So how to detect it? It is simple to query the Prev_inuse (P) of chunk after next chunk. The relevant code is as follows:
The entire operation is similar to the "merge backward" operation, and it is easy to understand the forward join operation of the free chunk by combining the comments with the preceding code. In this case, the current chunk is first, its next chunk is second, and the next chunk is top chunk, when the chunk bit of top prev_inuse is set to 1 (the previous chunk for top chunk, That is, second chunk, already in use), so the next chunk of first will not be "merged forward".
After you have introduced the forward and backward merge operations, you need to know how to further process the chunk after merging (or not merging due to the fact that the merge condition is not met). In glibc malloc, the merged chunk is placed in the unsorted bin (remember what unsorted bin means?). )。 The relevant code is as follows:
The complete process of the above code is briefly summarized as follows: inserting the current chunk into the first chunk of the unsorted bin (the first chunk is the head node of the linked list, is empty) and the second chunk (the first available chunk in the real sense) And then mark the previous chunk as used by setting your own Size field, and then change the Prev_size field of the chunk to set it to the size of the current chunk.
Note: the "previous" and "latter" chunk described in the previous paragraph refer to chunk that are connected by the chunk prev_size with the size word De Yin, that is, they are contiguous and contiguous in memory! Instead of using the chunk in the FD and BK fields in the bin (doubly linked list) in the previous and next chunk, remember!.
In this case, just add the first chunk to the unsorted bin.
2.2 Start Attack
Now let's analyze what happens if an attacker carefully constructs the input data in code [3] and overwrites the chunk header of second chunk with strcpy.
Assuming that the chunk header is overwritten with the relevant data as follows:
1) prev_size = An even number so that its prev_inuse bit is 0, which means that the previous chunk is free.
2) size = 4
3) FD = The Got table address of the free function address–12; (hereinafter, "Free addr–12")
4) BK = Shellcode Address
So what happens when the program calls free at [4]? Let's analyze it step by step.
One, backward merge
Because the previous chunk of first is not free, the backward merge operation does not occur.
Ii. Merging forward
Before judging whether a chunk is free, the previous article has been introduced, glibc malloc is judged by the following code:
PS: In this example, next chunk is second chunk, in order to facilitate the understanding of the text unified with next chunk.
As can be known from the above code, it is calculated by Nextchunk + Nextsize to point to the next chunk pointer, and then determine the next chunk the size of the prev_inuse tag bit. In this case, Nextsize is set to 4 so that glibc malloc will view the Prev_size field of next chunk as the size field of Next-next chunk, and we have the chunk of next prev_ The Size field is set to an even number, so the nextinuse obtained by the Inuse_bit_at_offset macro at this time is 0, that is, the next chunk is free! Now that next chunk is free, we need to merge forward, so we call unlink (Nextchunk, BCK, fwd); functions. The real focus is on this unlink function!
In the previous section 2.1 has introduced the implementation of the Unlink function, here in order to facilitate the description of attack ideas and procedures, and then detailed analysis again, the unlink code is as follows:
At this point P = nextchunk, BK = bck, FD = fwd.
1) First FD = NEXTCHUNK->FD = Free address –12;
2) Then bk = NEXTCHUNK->BK = shellcode start address;
3) The BK is assigned to FD->BK, i.e. (free address –12)->BK = shellcode start address;
4) Finally, FD is assigned to BK->FD, i.e. (shellcode start address)->FD = Free address –12.
The first two steps are OK to understand, mainly is the back 2 steps more confusing. We draw to understand:
The combination is a good understanding of the 3rd, 4 steps. Attentive friends have noticed that free addr-12 and shellcode addr corresponding prev_size fields are marked with dashed lines, why? Because in fact their corresponding memory is not chunk header, but in our attack we need to let glibc malloc in the unlink operation when they are forced to consider them as malloc_chunk structure. This is a good understanding of why you should replace the FD of next chunk with free addr–12, because (free addr-12)->BK is just the free addr, which means that the result of the 3rd step is to The data at addr is replaced with the start address of the shellcode.
Since the data at Free addr has been replaced with the start address of the Shellcode, the program executes the shellcode when it executes free again at code [5].
At this point, the whole unlink attack principle has been introduced, the rest of the work is based on the above principles, written shellcode. Just to be aware here, glibc malloc replaces 4 bytes of Shellcode + 8 position with free addr–12 in unlink, so the shellcode we write should skip the previous 12 bytes.
3 Confrontation Technology
Currently, the above unlink technology is obsolete (but not all of the unlink technology is invalid, see later), because glibc malloc to the corresponding security mechanism has been strengthened, specifically, is to add the following several security detection mechanisms.
3.1 Double Free detection
This mechanism does not allow the release of a chunk that is already in the Free State. Thus, when an attacker sets the size of second chunk to 4, it means that the size has a prev_inuse bit of 0, which means chunk before second chunk (we need free chunk) is already in the Free State, you will be given a double free error at this time. The relevant code is as follows:
3.2 Next size illegal detection
This mechanism detects whether the next size is between 8 and the total system memory size of the current arena. Therefore, when the next size of-4 is detected, the invalid next size error is reported. The relevant code is as follows:
3.3 Double-linked list collision detection
This mechanism detects whether the previous chunk FD in the list and the subsequent chunk BK in the unlink operation will point to the chunk that currently needs to be unlink. This way the attacker could not replace the FD and FD of second chunk. The relevant code is as follows:
4 Another unlink attack technique
Does the above 3-layer safety test mean that all unlink technologies fail? The answer is no, because the holes in the hole are always bigger! Just before I saw a good article (highly recommended), the presenter used unlink mechanism to implement heap overflow attack on Android4.4. As is known to all, the Android kernel is Linux-based, and its heap memory management is also used by glibc malloc, although somewhat different in some details, but the core principle is similar. The attack method described in this article successfully bypasses the above three-layer detection.
5 Summary
In this paper, the core principle of unlink attack technology is introduced in detail, although the unlink exploit technology described above has been ineffective, and the other unlink technology is more difficult, but we still need to study hard, because it can further deepen our glibc The understanding of the stack management mechanism of malloc, on the other hand, provides some ideas for subsequent heap overflow attack techniques.
As can be seen from the above analysis, unlink is mainly used in glibc malloc in the implicit link list mechanism, by covering the adjacent chunk data to implement the attack, then we can also find in the display linked list attack point? Follow the next article: Fastbin-based heap overflow exploit introduction.
Linux Technical Analysis series articles
Linux heap memory management in-depth analysis (i)
In-depth analysis of Linux heap memory management (bottom)
Go to the security, more security technical articles, please visit the Safety blog of Ali Poly
Exploitation of Linux heap overflow exploits unlink