how2heap

实验版本为ubuntu22.04 (2.35)

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
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


int main() {
printf("This technique will make use of malloc_consolidate and a double free to gain a UAF / duplication in the tcache.\n");
printf("It would also allow us to perform tcache poisoning if we had a heap leak.\n\n");

printf("Lets fill up the tcache to force fastbin usage...\n\n");

void *ptr[7];

for(int i = 0; i < 7; i++)
ptr[i] = malloc(0x40);
for(int i = 0; i < 7; i++)
free(ptr[i]);

void* p1 = calloc(1,0x40);

printf("Allocate another chunk of the same size p1=%p \n", p1);
printf("Freeing p1 will add it to the fastbin.\n\n");
free(p1);

void* p3 = malloc(0x400)

printf("To trigger malloc_consolidate we need to allocate a chunk with large chunk size (>= 0x400)\n");
printf("which corresponds to request size >= 0x3f0. We will request 0x400 bytes, which will gives us\n");
printf("a tcache-sized chunk with chunk size 0x410. p3=%p\n", p3);

printf("\nmalloc_consolidate will merge the fast chunk p1 with top.\n");
printf("p3 is allocated from top since there is no bin bigger than it. Thus, p1 = p3.\n");

assert(p1 == p3);

printf("We will double free p1, which now points to the 0x410 chunk we just allocated (p3).\n\n");
free(p1); // vulnerability

printf("So p1 is double freed, and p3 hasn't been freed although it now points to a free chunk.\n");
printf("We have thus achieved UAF on tcache!\n");

printf("We will request a chunk of size 0x400, this will give us the 0x410 chunk thats currently in\n");
printf("the tcache bin. p3 and p1 will still be pointing to it.\n");
void *p4 = malloc(0x400);

assert(p4 == p3);

printf("We now have two pointers (p3 and p4) that haven't been directly freed\n");
printf("and both point to the same tcache sized chunk. p3=%p p4=%p\n", p3, p4);
printf("We have achieved duplication!\n\n");

printf("Note: This duplication would have also worked with a larger chunk size, the chunks would\n");
printf("have behaved the same, just being taken from the top instead of from the tcache bin.");

return 0;
}

这里借用一下how2heap 2.35的fastbin dup consolidate实验

我们主要关注malloc_consolidate这个过程

过程分析

在函数19行那里

我们申请了一个堆快,地址为0x4048d0

image-20241125203943273

接着,我们释放这个堆快,可以看到被放到了fastbins里面

image-20241125204334206

我们再次申请0x400地址时,这个堆的地址出现在了原来申请的p1处

image-20241125204455491

不可能是直接从fastbin中拿地址出来的,这里出现了malloc_consolidate机制

简单来说就是先把fastbins中的值放进了top_chunk中,然后再从top_chunk获得地址的

那么什么情况下会有这样的机制呢,引用一下下面参考博客大佬的结论(具体源码看末尾的文章)

1._int_malloc中,当不能从fastbin中申请,且申请大小不属于small size时,如果当前arenafastbin chunk

2._int_malloc中,当无法通过top chunk分配,且arena中有fastbin chunk时

3._int_free中,释放到unsortedbin进行consolidation的过程中,在向前向后合并完成了以后,如果合并的大小超过0x10000

检查

  1. 在遍历的时候,会检查chunk的内存对齐
  2. 在遍历的时候,会检查chunk的大小和fastbin的大小是否匹配
  3. 在向前合并的时候,会检查prev_size和前一个chunk的size是否相同

在次过程后,结合上面实验的double free就可以伪造chunk了

版本

这个洞的版本抗性很高,2.35居然还能用

参考博客

堆利用详解:the house of rabbit(超详细) - 吾爱破解 - 52pojie.cn