how2heap 问题汇总(下)
字数 2033 2025-08-24 23:51:13

How2Heap 高级堆利用技术详解(下)

目录

  1. Small Bin 源码分析与 House of Lore 利用
  2. Poison Null Byte 漏洞的深入思考
  3. Unsorted Bin 攻击技术详解
  4. 总结与进阶建议

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;
        }
    }
}

关键点解析:

  1. Small bin 采用 FIFO(先进先出)原则
  2. bck = victim->bk 获取的是链表中前一个 chunk,因为 small bin 是双向链表
  3. 安全检查:bck->fd == victim 确保链表完整性
  4. 分配时会从链表尾部取出 chunk

1.2 House of Lore 攻击技术

House of Lore 攻击通过伪造 small bin 链表来实现任意地址分配。

攻击条件:

  1. 能够控制 small bin 中 chunk 的 bk 指针
  2. 能够绕过安全检查 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 | ...

验证条件:

  1. 第一次 malloc(p3) 时检查:victim->bk->fd == victimstack_buffer_1->fd == victim
  2. 第二次 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

关键点:

  1. 修改的 prev_size(nextchunk(P)) 是通过当前 chunk 的 size 找到的
  2. 在 free 操作后,chunk 合并利用的是下一个 chunk 的 pre_size 来定位前一个 chunk
  3. 只要不修改真实的 pre_size,就能完成 chunk 合并

2.3 进阶利用思路

  1. 通过增大 chunksize(P) 可以扩展可控内存区域
  2. 通过切割 unsortedbin 可以获得新的指针,实现变向的 UAF
  3. 可以在任意位置伪造 fake chunk 来满足检查条件

3. Unsorted Bin 攻击技术详解

3.1 Unsorted Bin 基本特性

  1. 当释放的 chunk 不适合 fastbin 时会进入 unsorted bin
  2. 分配时首先遍历 unsorted bin 寻找合适 chunk
  3. 不合适的 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));
}

关键检查条件:

  1. 大小必须与下一个请求不同
  2. 必须满足 2*SIZE_SZ (> 16 on x64) && < av->system_mem
  3. 伪造的 chunk size 要合理

3.3 Unsorted Bin 遍历机制

  1. 从头开始遍历 unsorted bin
  2. 遇到不合适的 chunk 会被移到对应的 small/large bins
  3. 找到第一个合适的 chunk 就停止遍历并使用
  4. 剩余的 chunk 保留在 unsorted bin 中

内存布局示例:

0x7fffffffddd0: 0x0000000000000000 | 0x0000000000000110  # stack_buffer
0x7fffffffdde0: 0x0000000000000000 | 0x00007fffffffddf0
0x7fffffffddf0: 0x0000000000000000 | 0x0000000000000110  # stack_buffer_1
0x7fffffffde00: 0x0000000000000000 | 0x00007fffffffddf0

Bins 状态变化:

  1. 初始状态:victim 在 unsorted bin
  2. 第一次 malloc 后:victim 被移到 small bin
  3. stack_buffer_1 仍保留在 unsorted bin

4. 总结与进阶建议

4.1 技术要点总结

  1. Small bin 攻击关键在于伪造双向链表并绕过完整性检查
  2. Poison null byte 利用 size 和 prev_size 的同步关系
  3. Unsorted bin 攻击需要控制遍历过程中的第一个合适 chunk

4.2 学习建议

  1. 深入阅读 glibc malloc 源码,理解每个检查条件的目的
  2. 通过调试实际漏洞程序加深理解
  3. 尝试组合不同技术实现更复杂的攻击
  4. 关注新版本 glibc 中的防护机制和绕过方法

4.3 防御措施

  1. 加强堆指针和链表完整性检查
  2. 实现更严格的 size 字段验证
  3. 引入随机化机制防止精确内存布局预测
  4. 及时更新到最新版本的 glibc

通过系统学习这些高级堆利用技术,可以深入理解堆管理器的内部机制,并提升漏洞挖掘和利用能力。建议结合具体漏洞案例进行实践练习,以巩固理论知识。

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 的处理逻辑如下: 关键点解析: 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 构造示例: 验证条件: 第一次 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 攻击示例代码 内存布局示例: 关键点: 修改的 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 攻击示例代码 关键检查条件: 大小必须与下一个请求不同 必须满足 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 中 内存布局示例: 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 通过系统学习这些高级堆利用技术,可以深入理解堆管理器的内部机制,并提升漏洞挖掘和利用能力。建议结合具体漏洞案例进行实践练习,以巩固理论知识。