House Of Orange

概述

作用:在程序没有free函数的情况下将一个chunk放到unsorted bin中

要求:能够控制top chunk的size域

利用原理

试想,当top chunk被耗尽时,再次申请一个chunk时,会发生什么?

malloc会调用sysmalloc来向系统申请内存,这其中又有两种方式,一种是通过sbrk进行内存的拓展,另一种是通过mmap函数独立映射一块内存

我们想要将剩下的top chunk分配到unsorted bin只有在sysmalloc通过sbrk拓展内存的时候才能实现

那么如何才能确保sysmalloc是调用的sbrk函数而不是mmap函数呢?

1
2
3
4
5
if (av == NULL
|| ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
&& (mp_.n_mmaps < mp_.n_mmaps_max)))
{
char *mm; /* return value from mmap call*/

这里检测要分配的大小是否大于mp_.mmap_threshold,默认为128kb,且mmap分配的内存块小于设定的最大值时,就会调用mmap来映射内存

所以要保证调用的时sbrk而不是mmap首先要保证分配大小小于128kb

sysmalloc中还存在以下检测

1
2
3
4
5
6
7
8
  /*
If not the first time through, we require old_size to be
at least MINSIZE and to have prev_inuse set.
*/
assert((old_top == initial_top(av) && old_size == 0) ||
((unsigned long) (old_size) >= MINSIZE &&
prev_inuse(old_top) &&
((unsigned long)old_end & pagemask) == 0));

这里验证了top chunk的合法性,第五行是在检测top chunk是否还未初始化,之后检测top chunk的size是否大于MINISEIZE以及top chunk的P位是否为1,最后检测top chunk的结束地址是否是页对齐的(一般内存页的大小是4kb)

那么我们要满足的条件有如下几点:

  1. 堆块申请的大小要小于128kb
  2. top chunk的size必须大于MINISIZE(0x10)
  3. top chunk的size必须小于申请的chunk size + MINISIZE
  4. top chunk的P位必须为1
  5. top chunk的结束地址必须是页对齐

之后剩下的top chunk就会通过_int_free进入到unsorted bin中

总结

house of orange堆利用手法适合在程序没有free函数时使用,作用是获得一块释放的堆块,在进行利用的时候涉及到对top chunk的控制,需要格外注意

题外话

可能有师傅和我一样心生疑惑:一定要更改top chunk的size域吗?通过多次申请chunk将top chunk耗尽再申请一个较大块的chunk来获得unsorted bin不行吗?

先说结论:经测试确实不行,原因不明,探究过程如下

先贴出我的测试程序

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>

int index = 0;

long long arr[100];

int menu() {

puts("0.new heap");

puts("1.free heap");

puts("2.write anywhere");

return puts("3.exit");

}

void new(){

int size;

puts("size?");

scanf("%d", &size);

arr[index] = malloc(size);

index++;

}

void del() {

int free_index;

puts("which do u want to free?");

scanf("%d", &free_index);

free((void *)arr[free_index]);

}

void anywhere() {

long long addr;

scanf("%x", &addr);

read(0, addr, 0x100);

}

int main() {

int choice;

while (1) {

menu();

scanf("%d", &choice);

if (choice == 0)

new();

else if (choice == 1)

del();

else if (choice == 2)

anywhere();

else if (choice == 3)

exit(0);

else

break;

}

return 0;

}

我是编译的2.23版本的,直接通过高版本编译然后patchelf到低版本的libc不行,如果有ubuntu16的虚拟机或者docker可以通过虚拟机或docker来编译,如果没有可以将其移动到how2heap里,通过脚本一键编译,也可以自寻他法(gcc指定库编译类的)

0

前两个应该是作为缓冲区留下的,我们先直接申请一个大小为132900的堆块

1

ok现在我们得到了一个较小的堆块了,我们继续申请一个大小为200的堆块,然后进入malloc函数看看发生了什么

2

成功进入sysmalloc函数

3

4

可以看到程序在执行了2554行代码后就开始进行收尾了

5

堆块成功拓展了,但是剩余的top chunk却没有进入unsorted bin,而是直接和新的top chunk合并到了一起

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
        /*
If MORECORE extends previous space, we can likewise extend top size.
*/
if (brk == old_end && snd_brk == (char *) (MORECORE_FAILURE))
set_head (old_top, (size + old_size) | PREV_INUSE);

else if (contiguous (av) && old_size && brk < old_end)
{
/* Oops! Someone else killed our space.. Can't touch anything. */
malloc_printerr (3, "break adjusted to free malloc space", brk,
av);
}

/*
Otherwise, make adjustments:

* If the first time through or noncontiguous, we need to call sbrk
just to find out where the end of memory lies.

* We need to ensure that all returned chunks from malloc will meet
MALLOC_ALIGNMENT

* If there was an intervening foreign sbrk, we need to adjust sbrk
request size to account for fact that we will not be able to
combine new space with existing space in old_top.

* Almost all systems internally allocate whole pages at a time, in
which case we might as well use the whole last page of request.
So we allocate enough more memory to hit a page boundary now,
which in turn causes future contiguous calls to page-align.
*/

else
{

libc2.23malloc.c第2543行起↑

这里有三个条件判断,而我们需要的_int_free (av, old_top, 1);位于最后一个else语句里,这里进入第二个分支导致无法进入第三个分支释放旧的top chunk

疑惑:在执行malloc_printerr (3, "break adjusted to free malloc space", brk,av);时程序不应该终止吗,难道调试器欺骗了我?

通过修改top chunk的size来达成利用条件时是成功了的

师傅们恕我能力不足只能列出现象,原因至少现在的我还无法解决,如果您看到了这里且有确切的答案,我将不胜感激如果你能通过本博客提供的联系方式联系到我,也欢迎与我一起讨论