首页
社区
课程
招聘
how2heap调试学习(一)
发表于: 2020-12-5 22:42 14813

how2heap调试学习(一)

2020-12-5 22:42
14813

字数限制,分开发了

代码: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 

运行一下看看

image.png

程序展示了一个 glibc 堆分配策略,first-fit。在分配内存时,malloc 先到 unsorted bin(或者 fastbins)中查找适合的被 free 的 chunk,如果没有,就会把 unsorted bin 中的所有 chunk 分别放入到所属的 bins 中,然后再去这些 bins 里去寻找适合的 chunk。可以看到第三次 malloc 的地址和第一次相同,即 malloc 找到了第一次 free 掉的 chunk,并把它重新分配


下断点,对着源码调试着理解一下


先是 malloc 了两次,然后给第一个 a 赋了 "AAAAAAAA"

image.png

然后 free 了 a,这时候 a 被放到了 unsorted bin 中

image.png

然后再去申请一个小于 free chunk 的大小的内存空间根据 first fit 就会分配到这里

可以发现,当释放了一块内存之后再去申请一个大小略小的空间,那么 glibc 倾向于将先前释放的空间重新分配

image.png

加上参数重新编译一个版本:gcc -fsanitize=address -g first_fit.c

会提示有个 use-after-free 漏洞

image.png

UAF 漏洞简单来说就是第一次申请的内存释放之后,没有进行内存回收,下次申请的时候还能申请到这一块内存,导致我们可以用以前的内存指针来访问修改过的内存


来看一下一个简单的 UAF 的利用的例子

看一下,首先申请了一个 chunk,把那个 p1[1] 改成了 echo 函数的地址

image.png

free 掉之后再申请一个大小相同的 p2,这时候会把之前 p1 的内存区域分配给 p2,也就是说可以用 p2 来控制 p1 的内容了

image.png

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

image.png

第一个 free 之后,chunk a 被添加到 fastbins 中

image.png

image.png

第二个 free 之后,chunk b 被添加到 fastbins 中,可以看到在 b 的 fd 指针那里已经改成了 chunk a 的地址了

image.png

image.png

此时,由于 chunk a 处于 bin 中第 2 块的位置,不会被 double-free 的检查机制检查出来,所以第三个 free 之后,chunk a 再次被添加到 fastbins 中:

image.png

chunk a 和 chunk b 形成了一个环

image.png

再 malloc 两个的情况(上面那种情况先 q 再 c)

image.png

后来又 malloc 了一个可以看到 0x4444444444444444 被改成了 0x4646464646464646

是因为后来申请的 f 跟 d 指向同一块内存区域

image.png

所以,对于 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 之后

image.png

三次 free 之后,可以看到由于 double free 造成的循环的指针

image.png

这时候我们再去 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));

image.png

这样 malloc 一次之后再次申请的时候会申请到 fd 指针指向的 0x00007fffffffdcb0

image.png

ubuntu16.04 glibc 2.23

gcc -g fastbin_dup_consolidate.c

这个例子展示了在 large bin 的分配中 malloc_consolidate 机制绕过 fastbin 对 double free 的检查


一开始分配了两次之后:

image.png

释放掉 p1 之后,放到了 fastbins 中

image.png

此时分配了一个 large chunk 即:void *p3 = malloc(0x400);

fastbins 中的 chunk 已经没有了,在 small bins 出现了,同时 chunk 2 的 size 和 prev_size 都被修改了

image.png

在分配 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

image.png

再一次 malloc 之后会从 fast bins 中分配

void *p4 = malloc(0x10);

strcpy(p4, "CCCCCCC");

image.png

再一次就是从 small bins 中分配

void *p5 = malloc(0x10);


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-12-6 12:16 被yichen115编辑 ,原因: 排版
收藏
免费 6
支持
分享
最新回复 (2)
雪    币: 589
活跃值: (205)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
tql,菜鸡跟着学习学习
2020-12-6 13:05
0
雪    币: 853
活跃值: (1417)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
来了老哥
2022-5-20 20:38
0
游客
登录 | 注册 方可回帖
返回
//