mp_.tcache_bins基本漏洞利用
Thursday, February 23, 2023
本文共1345字
3分钟阅读时长
⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/principle/mp_.tcache_bins%E5%9F%BA%E6%9C%AC%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8/。商业转载请联系作者获得授权,非商业转载请注明出处!
It’s not what you look at that matters, it’s what you see.
— Henry David Thoreau
什么是mp_结构体?
我们可以在identifier - Glibc source code (glibc-2.37) - Bootlin搜索mp_,会发现它是一个内部链接的全局变量,类型是malloc_par结构体:
这说明它不会出现在libc的符号表中,需要通过gdb调试获取偏移:
而通过它的名字和赋值我们也可以很清晰地猜测到,这个tcache_bins域是用来记录tcache bin的最大索引值的,超过这个索引值的堆块都不属于tcache bin。
这个索引值是通过堆块的大小计算的。之所以要计算这个索引值,是因为所有的bin存在一个大小为136的数组里面,tcache bin、large bin等都管理一定范围内的bin。通过大小计算这个索引可以很方便地判断一个堆块应属哪个bin
mp_.tcache_bins有什么用?
那么这个mp_.tcache_bins有什么用呢?
可以看到,如果我们想要伪造一个大chunk,让它以tcache的方式被获取(这样就可以使用与tcache相关的攻击手段攻击),我们需要伪造以下两个值:
- mp_.tcache_bins足够大。可以通过unsorted bin attack(高版本不可用)或者large bin attack等方式向mp_.tcache_bins内写入一个足够大的值实现
- tcache->counts[tc_idx] > 0。
第二点如何实现呢?我们如何更改这个counts值呢?
因为tcache结构体是存放在堆上的(通常是第一个堆块),当然可以使用其他方式覆写counts值,但在这里其实可以利用tcache bin本身的漏洞。
当mp_.tcache_bins足够大的时候,我们是可以将一个大chunk放进tcache bin中的,只是由于tcache分配在堆上,这个索引值又太大,所以这个大chunk的地址(链表头)会被放进相邻的chunk中
同时,tcache_get里也没有对越界的检查:
PS. 其中,if (__glibc_unlikely (!aligned_OK (e)))malloc_printerr ("malloc(): unaligned tcache chunk detected");
这段代码的作用是检查从tcache中获取的内存块的地址是否按照指定的对齐方式对齐(__glibc_unlikely
用于编译器优化),这些都和越界无关
同时,tcache_put也允许我们放入一个大chunk,甚至链表头都是不加密的
因此,如果我们可以控制相邻堆块,那么我们释放的大堆块所属的链表头也是可控的。
具体应该如何操作?
以上这一通操作能够实现的前提是mp_.tcache_bins通过unsorted bin attack或者large bin attack等方式增大
mp_.tcache_bins = mp_ + 0x50 = mp_ + 80,如果用large bin attack覆写,要写入的地址是mp_ + 0x30。large bin attack的具体解析见我的另一篇文章Largebin_Attack - P3troL1er 的个人博客
然后我们要释放一个大小为N的大堆块p1进入tcache bin,然后记下它的地址(可以通过下断点到free那里查看,也可以通过heap等命令查看堆分布获取)
然后通过x/150gx或者tele命令找到这个地址存放的位置和我们可控的相邻chunk头部的差值
这里感谢群里L0tus和h4kuy4等师傅的耐心指导,这三张图也是来自他们~
然后我们就可以将链表头地址覆盖为__free_hook等,实现getshell。
如果有什么问题或者建议,欢迎在评论区评论指出~
扫码阅读此文章
点击按钮复制分享信息
点击订阅