首页
社区
课程
招聘
[原创]Tcache安全机制及赛题详细解析(gundam && House of Atum)
发表于: 2023-7-21 00:45 18748

[原创]Tcache安全机制及赛题详细解析(gundam && House of Atum)

2023-7-21 00:45
18748

glibc 源码网址:https://elixir.bootlin.com/glibc/glibc-2.26/source/malloc/malloc.c


    ptmallloc2在libc2.26中引入了Tcache这种无需对arena上锁就可以使用的小堆块。tcache是单链表结构,每条链上最多可以有 7 个 chunk,free 的时候当对应的 tcache bin 满了才放入fastbin,unsorted bin,malloc的时候优先去tcache bin找。


其数据结构如下。

    每个线程默认64个单链表结构的bins,每个bins最多存放7个chunk。chunk在64位机器以16字节递增,从24到1032字节。在32位机器上以8字节递增,从12到512字节。因此tcache只能存放non-large的chunk。


图解

释放堆块时:如果chunk是non-large chunk,并且对应bins未满7个,则放入对应bins。

分配堆块时:

(1)如果fastbins或者small bins中成功返回一个需要的chunk,那么对应fastbins或者small bins中的剩余chunk会被放进相应的tcache bin中,直到相应tcache bin填满7个或者对应的fastbins或者small bins为空。chunk在tcache bin中顺序与fastbin相反,与small bin中顺序相同。

(2)unsorted bin 中符合用户要求的的chunk取出时,chunk 合并等其他操作,每一个符合要求的chunk会优先放入tcache,然后从 tcache 中返回其中一个。如果tcache已满则直接返回。

从tcache中取出堆块。

(1)在__libc_malloc()调用_int_malloc()前,如果tcache bin中有符合要求的chunk,则直接返回。

(2)(默认不执行)。在unsorted bin最后如果找到了可以返回的块,并且 mp_.tcache_unsorted_limit(默认为0) 次数小于处理 unsorted count(即tcache中装满了对应的chunk)那么就会从其中拉出一个chunk出来返回。

(3)在unsorted bin的遍历之后 如果unsorted bin中存在可以返回的chunk 那么在遍历unsorted bin之后,则调用一次tcache_get返回给用户使用。

tcache中的chunk不会合并。chunk的prev_inuse=1。


    __libc_malloc()使用request2size()转换堆块为实际大小时,不会进行整数溢出检查。请求一个接近(SIZE_MAX)的堆块将导致溢出,使malloc错误返回tcache bin中的堆块。


源码

使用glibc-2.26的输出,分配成功。

使用glibc-2.27的输出,nil说明漏洞已修复。

libc-2.29新增加double free检查,方法是在tcache_entry结构体中新增加标志位key来检查chunk是否在tcache bin中。当 free 掉一个堆块进入 tcache 时,假如堆块的 bk 位存放的key == tcache_key, 就会遍历这个大小的 Tcache ,假如发现同地址的堆块,则触发 double Free 报错。因为chunk的key保存在bk位置,只需将其修改即可绕过double free检查。


说明:附件中的赛题已经用patchelf改好环境。

1.修改rpath。

2.检查保护。

3.试运行。

可见为菜单题。

1-创建一个gundam机器人

2-访问gundamu

3-销毁一个gundam

4-炸毁工厂

5-退出


4.逆向分析。


1-分析Build函数

不难分析出gundam结构体

2-Visit函数

3-Destroy函数

4-BlowUp函数

5.漏洞利用


(1)利用unsorted bin attack泄露main_arean地址进而泄露libc基址。


申请9个chunk,释放7个填满tcache,在释放一个进入unsorted bin,剩下一个阻隔top chunk防止合并。


可以看到unsorted bin中的chunk的fd和bk指向了一个栈地址(main_arena+88)。

blow up后

计算这个栈地址与libc基地址的偏移。

偏移为:0x3dac78

在申请8个chunk,将unsorted bin中的chunk申请出来,再利用visit()函数泄露main_arena+88处的栈地址。


此时需要注意,chunk优先从tcache取出,然后Type[7]才是unsorted bin中的chunk。由于第8个chunk的fd指向main_arena+88处的地址,


所以此时只需要接收6个字节(因为64位栈地址前2字节为'\x00',并且用%s打印地址)然后用'\x00'补齐即可。


再用main_arena+88处的地址减去上面计算出的固定偏移即可得到栈的基地址。

进而可以由libc-2.26.so得到system和__free_hook地址。


(2)利用double free制造tcache poisoning到&__free_hook


依次释放2,1,0,0。此时tcache bin状态如下。

blow up 后

已经形成了double free。此时在申请一个堆块将会把chunk0申请出来,将其内容改为__free_hook的地址。


因为此时chunk0依然在tcache bin(0x110)的链上,所以__free_hook会被挂在tcache bins的链上。

(3)将物理堆块为chunk0,逻辑为chunk1的factory[1]_buf改写为'/bin/sh\x00',修改__free_hook为system地址。


修改factory[1]_buf为'/bin/sh\x00'

此时tcache bin中还剩下__free_hook地址。

再次申请得到__free__hook+0x10处的堆块,此时修改__free_hook为system。

(4)free('/bin/sh\x00');


最后 destory(1),也就是free('/bin/sh\x00')即可getshell


1.修改rpath


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-10-14 20:14 被jelasin编辑 ,原因:
上传的附件:
收藏
免费 8
支持
分享
最新回复 (5)
雪    币: 3090
活跃值: (30881)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-7-21 10:15
0
雪    币: 3948
活跃值: (6530)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
3
秋狝 感谢分享
这帖子是不是有bug,怎麼老token check err
2023-7-21 17:17
0
雪    币: 26205
活跃值: (63302)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
4
jelasin 这帖子是不是有bug,怎麼老token check err
应是bug,我们排查一下原因
2023-7-21 18:38
0
雪    币: 3090
活跃值: (30881)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
jelasin 这帖子是不是有bug,怎麼老token check err
确实是有bug
2023-7-21 20:47
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
大牛能联系我吗? 无法私信,有事相求
2024-7-30 22:20
0
游客
登录 | 注册 方可回帖
返回
//