Unsortedbin Attack 基本介绍
参考资料:https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/unsorted-bin-attack/
UnSortedbin Attack 概述
unsortedbin attack 顾名思义,该攻击和 Glibc 堆管理中的 Unsortedbin 的机制息息相关 。
unsortedbin attack 被利用的前提是控制 UnSorted Bin Chunk 的 bk 指针
unsortedbin attack 可以达到的效果是实现修改任意地址值为一个较大的数值。
UnSortedbin Attack 回顾
unsortedbin attack 作为一种久远的攻击方式,尝尝作为其他攻击方式的辅助手段,比如修改 global_max_fast 为一个较大的值,使得几乎所有大小的 chunk 都用 fastbin 的管理方式进行分配和释放,又或者修改 _IO_list_all 来伪造 _IO_FILE 进行攻击。在上述攻击的利用过程中我们实际上并不需要对unsortedbin的分配过程有太多了解
global_max_fast 是 main_arena 中控制最大 fastbin 大小的变量
unsortedbin 的结构
unsortedbin 在管理时为循环双向链表,若 Unsorted Bin 中有两个 bin,那么该链表结构如下

在该链表中必有一个节点(不准确的说,是尾节点,这个就意会一下把,毕竟循环链表实际上没有头尾)的 fd 指针会指向 main_arena 结构体内部。

倘若只有一个 bin,那么该链表的 fd 和 bk 指针都指向它本身。
UnSortedbin 的基本来源
- 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。
- 释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。
- 当进行 malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。malloc_consolidate(对堆中的碎片进行整理,减少堆中的碎片)。
unsortedbin 的使用
- 在 unsortedbin 的使用过程中,采用的遍历顺序是 FIFO(First In Frist out)先进先出,即插入的时候插入到 unsortedbin 的头部,取出的时候从链尾获取,因此 unsortedbin 遍历堆块的时候使用的是 bk 指针。
- 在程序进行 malloc 时,如果在 fastbin,smallbin 中找不到对应大小的 chunk,就会尝试从 unsortedbin 中寻找 chunk。如果取出的 chunk 大小正好满足,就会直接返还给用户,否则就会把这些 chunk 分别插入到相应的 bin 中。
UnsortedBin Attack 原理
1 |
|
可以看一下 glibc 的源码,当将一个 unsortedbin 取出时,会将 bck->fd 的位置写入 UnSortedbin 的位置,换而言之:如果我们控制了 bk 的值,就可以将 unsorted_chunk(av)写到任意地址。
以下通过一个实例来掩饰 unsortedbin_attack 的原理,目标是通过攻击将 stack_var 改成一个很大的值。
1 |
|
执行之前,先给程序换一个低版本的 libc
1 | patchelf --set-interpreter ./glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so ./test1 |
下面开始对程序进行调试:我们直到stack_var 初始值为 0,运行到这里看一下:
stack_var&p 的初始值
1 | ──────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────── |
我们可以看到:
此时stack_var 值为 0,地址为0x7fffffffdce0;p 的值为0x7fffffffddd0,地址为0x7fffffffdcd8。
unsigned long *p=malloc(0x410);
继续让程序执行 unsigned long *p=malloc(0x410);,继续查看内存:
1 | ──────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────── |
malloc(500);
继续执行 malloc(500);此时创建了两个堆块,这里是为了避免 chunk1 和 top_chunk 相邻而导致在 freechunk1 时无法会受到 unsortedbin 当中。当我们释放一个不属于 fastbin 的 chunk ,并且该 chunk 不和 top_chunk 相邻,该 chunk 会被首先放到 unsortedbin 当中,相邻则被放在 top_chunk
1 | pwndbg> heap |
继续 n 执行 free(p);
1 | ───────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────── |
我们之前了解到,当 unsortedbin 之后一个 free_chunk 时,他的fd和bk指针都指向 unsortedbin 本身。

执行p[1]=(unsigned long)(&stack_var-2);
p[1]等价于*(p+1),即p指向的地址偏移 1 个元素长度的位置(比如p是 8 字节指针,p[1]就是p+8的地址)
p[1]等价于(p+8)= (0x602010+8)= 0x602018这正是 chunk 的bk字段的地址!
stack_var的地址是0x7fffffffdcd8(rbp-0x18);
&stack_var - 2 = 0x7fffffffdcd8 - 0x10 = 0x7fffffffdcc8
1 | ───────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────── |
攻击本质:把 chunk 的bk指针从main_arena地址改成&stack_var-2(栈地址),这一步依赖 “UAF(释放后使用)” 漏洞 ——free (p) 后仍能修改 p 指向的内存。

- 原 chunk
bk:0x7ffff7bc3b78(main_arena 地址,unsorted bin 的尾节点); - 新 chunk
bk:0x7fffffffdcc8(栈上stack_var偏移 2 个 long 的地址); - 最终 unsorted bin 的
BK链指向了栈地址0x7fffffffdcc8,而非 libc 的 main_arena。
执行malloc(0x410);
在执行 malloc(0x410)时,会判断所申请的 chunk 处于 smallbin 所在的范围,但此时 smallbin 中并没有空闲的 chunk,所以会从 unsortedbin 中寻找,发现 unsortedbin 不为空,于是把 unsortedbin 中的最后一个 chunk 拿出来。(先进先出原则 FIFO)
1 | pwndbg> unsortedbin |
核心原理:当调用malloc(0x410)时,glibc 会从 unsorted bin 中查找匹配大小的 chunk,执行链表维护逻辑:
1 | // glibc底层逻辑(简化) |
- bck->fd = (&stack_var-2) + 8 = &stack_var(因为 fd 字段在 chunk 中偏移 8 字节);
- &stack_var-2:64 位下unsigned long占 8 字节,-2等价于地址减0x10(即0x7fffffffdcc8)
- 最终:unsorted_chunks(av)(unsorted bin 的地址)被写入stack_var的地址,stack_var的值从 0 变成这个高地址(“超大数”)。



总结
首先我们将一个堆块释放到 unsortedbin 当中,然后利用堆溢出修改 unsortedbin 中的 chunk 的 bk 指针,这个 bk 指针指向 target_addr-0x10。当我们用 malloc 申请 unsortedbin 中的堆块时,target_addr 中的值就会变成 main_arena+88 地址的值# target_addr:目标地址(想要修改为超大数的地址)。
更新: 2026-03-09 13:21:34
原文: https://www.yuque.com/idcm/wnemg9/qq62i2u19syawd01