堆管理结构的利用
在面试中被问到unsortedbin attack的写入值的意义,知道是main_areana+88的位置,但是具体的意义以及利用方式却没有深究过。记录一下对于两个堆管理结构的学习笔记:main_arena以及tcache_perthread_struct的结构学习
Main_arena
全局一个,位于glibc模块的内存附近,用于管理进程中主堆(用sbrk分配),是arena环形链表的头节点。arena环形链表的非头节点为thread arena,通过mmap分配。
libc中对于main_rena的定义
这里用的是2.35的源码
1 | struct malloc_state |
这里还有个全局唯一的mp_,作为堆分配的
配置策略以及记录arena的统计中心
这里定义main_arena用了C 语言的 指定初始化器,具体解释可以见https://blog.csdn.net/weixin_42258222/article/details/105221108
堆管理的结构实际上是malloc_state,而main_arena的定义其实就是初始化了一些malloc_state的成员,具体意义在注释中解释。
这里解释一下线程附着在arena的意义:
- 线程第一次调用
malloc时,glibc 会根据线程 ID 做哈希,从环形链表挑一个 arena;- 若该 arena 当前空闲(
attached_threads == 0),就把计数 +1,同时把线程的tcb->arena指针指向它——此时称线程“附着”到这块 arena;- 线程后续再 malloc/free 都直接复用这块 arena,无需重新哈希
- 线程退出或调用
malloc_consolidate迁移时,计数减 1;减到 0 表示没有任何线程再用它,这块 arena 就可以被整个释放或回收进全局缓存。
这里详细解释一下其中的bin数组:
1 | // 索引布局: |
tcache_perthread_struct
管理对应线程的tcache,存储在堆内存开头,自身作为一个chunk被管理,在第一次需要时动态创建,一般是内存中第一个chunk。2.35版本下的源码:
1 | typedef struct tcache_entry |
利用实战
TSctf-2025的uniform,题目中给了固定大小的chunk无限次uaf。考虑打unsortedbin attack攻击,攻击buf数组(用来存堆指针的数组)中某一索引,实现对于main_arena中自top成员后0x80大小的控制权。修改top指针可以实现迁移top_chunk而达到任意地址分配,当然这里注意对应位置要符合16位地址对其以及pre_size位为1。这里题目刚好存在一个全局变量在buf数组前面,构造此buf为一个合法且足够分配0x90大小chunk的top_chunk size,然后再通过main_arena修改将top_chunk迁移并修复unsorted_bin,分配就能控制buf数组啦。

构造后的main_arena中top指向buf

成功将堆分配到buf字段
通过envirno泄露栈地址并覆盖返回值为rop链即可。
Poc.py
1 | from pwn import * |