UnSortedbin Attack 例题分析
参考资料:https://www.cnblogs.com/youdiscovered1t/p/19109746 特别好的一篇文章,很详细!!!
BUUCTF 0ctf_2017_babyheap


1 | int sub_CF4() |
Allocate
先遍历 16 个索引,寻找到第一个未在使用的索引,读取用户输入的数据大小,要求小于 4096 个字节
分配内存:calloc(j,1) = 分配 j 字节,且自动初始化为0(区别于malloc) v3 =calloc ( j, 1u ) ;
if ( !*(_DWORD *)(24LL * i + a1) ):
1 | 24 分别指的是 |
Fill
1 | __int64 __fastcall sub_E7F(__int64 a1) |
这一部分其实不难理解,首先读取用户输入的 index,然后去寻找 index 对应的 chunk。之后进行(_DWORD)i 的判断,如果=1 就可以进行信息的输入sub_11B2(*(_QWORD *)(24LL * n0x10_1 + a1 + 16), n0x10_2);
看一下 sub_11B2,该函数就相当于 read 函数,可以读取信息放入到(24LL * n0x10_1 + a1 + 16) 当中,
也就是存放数据的 user_data 处。
Free
这一部分也就是分别对前面说的三个区域置 0,并且 free 掉我们的 chunk
Dump


输出程序,把对应索引的 user_data 存入的数据都打印出来。
攻击思路:
1 | from pwn import * |


此时 fastbin 当中会存在两个链表 chunk2 ->chunk1,我们看一下此时的 chunk
此时 chunk2 的 fd 指针指向了 chunk1,在0x55be3471c050 的地址中存放着 chunk1 的地址。
我们可以通过堆溢出去进行堆 chunk2 当中的 fd 指针进行修改,让他指向 chunk4
1 | from pwn import * |
p8(0x80)修改最低字节的两位,其他字节不会影响
此时 Fastbin 当中的链表就不再是 chunk2->chunk1 了,而是 fastbin[0x20 链表头] → chunk2 → chunk4
此时chunk4虽然没有被free,但已经存在于bin中,若此时在此申请chunk,根据程序Allocate的功能,又会出现一个指向chunk4的结构,也就是完成了双指
再一次动态申请 chunk4
在申请之前,有两个问题:
- Fast Bin符合LIFO,即后进先出,那么先出的就是chunk2而非chunk4,因此我们需要Allocate两次
- malloc的检查
malloc的检查什么意思呢?
我们知道,在Fast Bins中,每个Fast Bin里面的chunk的大小都是一致的。原先chunk1的size大小是0x21,chunk1就会被存储在chunk大小都为0x20的Fast bin中
那当我们再次malloc一个0x10大小的chunk的时候,就会去chunk大小都为0x20的Fast bin中去查找,但是此时找到一个大小为0x90的chunk,malloc就会检查出异常,因而程序终止。
因此我们这次通过举例 chunk4 较近的 chunk3 来进行堆溢出去修改 chunk4 的 size 段绕过 glibc 的判断
1 | from pwn import * |
我们修改了p8(0x21)就可以成功绕过 malloc 的检查


接下来就是泄露的预处理部分了,即先让chunk4进入Unsorted Bin
之前也提到过,要让其进入Unsorted Bin需要满足两个条件:
- 释放(free)的chunk大小不属于fast bin的范围
- 该chunk不和top chunk紧邻时
关于第一条,我们只需要将其大小改回去(0x21 >> 0x91),然后free即可
关于第二条,由于chunk4是最晚申请的,他就挨着top chunk,我们也可以通过动态调试来验证这一点
1 | from pwn import * |

chunk4成功进入unsortedbin,且出现特征:如果usorted bin中只有一个bin ,那么它的fd和bk指针会指向同一个地址,就是unsorted bin链表的头部 ( main_arena+88 )
关于计算 libc 基址,我们知道 smallbins,largebins,unsortedbins 统一存放在 malloc_state 这样一个结构体的一个数组当中。malloc_state 是属于 main_arena 的。并且 main_arena 是一个全局变量,位于 libc 的数据段。
如果我们知道了上述情况当中的 fd/bk 指针所指向的地址,那我们也就相当于知道了 main_arena 的基址,从而可以知道 libc 的基址
下面我们需要做的就是进行偏移量的测定。main_arena+88 指向的就是 unsorted bin 的链表头(fd 指针)
因此我们可以通过泄露 fd 指针的值,去寻找 main_arena
更新: 2026-03-09 19:56:40
原文: https://www.yuque.com/idcm/wnemg9/ag4ilhe8akdtsphx