字数限制,分开发了
代码: https://github.com/yichen115/how2heap_zh
代码翻译自 how2heap: https://github.com/shellphish/how2heap
本文语雀文档地址: https://www.yuque.com/hxfqg9/bin/ape5up
每个例子开头都标着测试环境
ubuntu16.04 glibc 2.23
源码:
编译一下:gcc -g first_fit.c
运行一下看看
程序展示了一个 glibc 堆分配策略,first-fit。在分配内存时,malloc 先到 unsorted bin(或者 fastbins)中查找适合的被 free 的 chunk,如果没有,就会把 unsorted bin 中的所有 chunk 分别放入到所属的 bins 中,然后再去这些 bins 里去寻找适合的 chunk。可以看到第三次 malloc 的地址和第一次相同,即 malloc 找到了第一次 free 掉的 chunk,并把它重新分配
下断点,对着源码调试着理解一下
先是 malloc 了两次,然后给第一个 a 赋了 "AAAAAAAA"
然后 free 了 a,这时候 a 被放到了 unsorted bin 中
然后再去申请一个小于 free chunk 的大小的内存空间根据 first fit 就会分配到这里
可以发现,当释放了一块内存之后再去申请一个大小略小的空间,那么 glibc 倾向于将先前释放的空间重新分配
加上参数重新编译一个版本:gcc -fsanitize=address -g first_fit.c
会提示有个 use-after-free 漏洞
UAF 漏洞简单来说就是第一次申请的内存释放之后,没有进行内存回收,下次申请的时候还能申请到这一块内存,导致我们可以用以前的内存指针来访问修改过的内存
来看一下一个简单的 UAF 的利用的例子
看一下,首先申请了一个 chunk,把那个 p1[1] 改成了 echo 函数的地址
free 掉之后再申请一个大小相同的 p2,这时候会把之前 p1 的内存区域分配给 p2,也就是说可以用 p2 来控制 p1 的内容了
ubuntu16.04 glibc 2.23
fastbin 主要是用来放一些小的内存的,来提高效率
源码
gcc -g fastbin_dup.c
程序展示了 fastbins 的 double-free 攻击,可以泄露出一块已经被分配的内存指针。fastbins 可以看成一个后进先出的栈,使用单链表来实现,通过 fastbin->fd 来遍历。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk,所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过了检查顺利执行,然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针
(之前 gef 调的因为地址一样就没换图片)
首先 malloc 3 个 chunk
第一个 free 之后,chunk a 被添加到 fastbins 中
第二个 free 之后,chunk b 被添加到 fastbins 中,可以看到在 b 的 fd 指针那里已经改成了 chunk a 的地址了
此时,由于 chunk a 处于 bin 中第 2 块的位置,不会被 double-free 的检查机制检查出来,所以第三个 free 之后,chunk a 再次被添加到 fastbins 中:
chunk a 和 chunk b 形成了一个环
再 malloc 两个的情况(上面那种情况先 q 再 c)
后来又 malloc 了一个可以看到 0x4444444444444444 被改成了 0x4646464646464646
是因为后来申请的 f 跟 d 指向同一块内存区域
所以,对于 fastbins,可以通过 double-free 泄露一个堆块指针,可以用 -fsanitize=address 参数重新编译看看
在 libc-2.26 中,即使两次 free,也没有触发 double-free 的异常检测,这是因为 tcache 的机制有关,等后面介绍
ubuntu16.04 glibc 2.23
源码
gcc -g fastbin_dup_into_stack.c
这个程序展示了怎样通过修改指针,将其指向一个伪造的 free chunk,在伪造的地址处 malloc 出一个 chunk。该程序大部分内容都和上一个程序一样,漏洞也同样是 double-free,只有给 fd 填充的内容不一样
三次 malloc 之后
三次 free 之后,可以看到由于 double free 造成的循环的指针
这时候我们再去 malloc 两次,还剩一个指向 chunk a 的 free chunk,而前面我们也申请到了指向它的 chunk d,可以通过它编辑 chunk a 的 fd 指针,填充一个有意义的地址:栈地址减 0x8(因为伪造的 chunk 要有个 size,size 在 &stack_var - 0x8 的位置上)
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
这样 malloc 一次之后再次申请的时候会申请到 fd 指针指向的 0x00007fffffffdcb0
ubuntu16.04 glibc 2.23
gcc -g fastbin_dup_consolidate.c
这个例子展示了在 large bin 的分配中 malloc_consolidate 机制绕过 fastbin 对 double free 的检查
一开始分配了两次之后:
释放掉 p1 之后,放到了 fastbins 中
此时分配了一个 large chunk 即:void *p3 = malloc(0x400);
fastbins 中的 chunk 已经没有了,在 small bins 出现了,同时 chunk 2 的 size 和 prev_size 都被修改了
在分配 large chunk 的时候,首先会根据 chunk 的大小来获取对应的 large bin 的 index,然后判断 fast bins 中有没有 chunk,如果有就调用 malloc_consolidate() 合并 fast bins 中的 chunk,然后放到 unsorted bin 中。unsorted bin 中的 chunk 会按照大小放到 small 或 large bins 中
p1 已经不再 fastbin 的顶部,所以可以再次 free
p1 既在 small bins 又在 fast bins
再一次 malloc 之后会从 fast bins 中分配
void *p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
再一次就是从 small bins 中分配
void *p5 = malloc(0x10);
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-12-6 12:16
被yichen115编辑
,原因: 排版