how2heap 问题汇总(上)
字数 1492 2025-08-25 22:59:09

How2Heap 问题解析与教学文档

1. 内存分配基础概念

1.1 Bin 的分类

在 glibc 的内存分配器中,free 后的 chunk 会根据大小被放入不同的 bin 中:

  • fastbins: 用于小内存块的快速分配 (通常小于等于 0x80 字节)
  • unsortedbin: 所有非 fastbins 的 chunk 被 free 后首先进入这里
  • smallbins: 用于中等大小的内存块 (通常小于 512 字节)
  • largebins: 用于大内存块的分配

1.2 Unsorted Bin 的特殊性

Unsorted bin 有以下特点:

  • 所有非 fastbins 大小的 chunk 被 free 后首先进入 unsorted bin
  • 只有一个链表结构(不是复数形式)
  • 在 malloc 时充当缓冲区角色
  • 当无法满足分配请求时,会将 chunk 转移到合适的 smallbins 或 largebins

2. First Fit 分配策略分析

2.1 基础示例分析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char* a = malloc(512);
    char* b = malloc(256);
    free(a);
    char* c = malloc(500);
}

调试观察:

  1. free(a) 后,512 字节的 chunk 进入 unsorted bin
  2. malloc(500) 时直接从 unsorted bin 中分配

2.2 Remainder Chunk 现象

修改示例:

int main() {
    char* a = malloc(512);
    char* b = malloc(256);
    free(a);
    char* c = malloc(10);  // 只取走 0x20 字节
    char* d = malloc(512);
}

观察:

  1. malloc(10) 从 unsorted bin 中切割出 0x20 字节
  2. 剩余 0x1f0 字节成为 remainder chunk 仍留在 unsorted bin
  3. malloc(512) 时 remainder chunk 不够大,从 top chunk 分配
  4. remainder chunk 被转移到 smallbins

3. Consolidate 机制深入研究

3.1 极端示例分析

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main() {
    void* p1 = malloc(0x70);
    void* p3 = malloc(0x70);
    void* p4 = malloc(0x70);
    void* p5 = malloc(0x70);
    void* p6 = malloc(0x70);
    void* p7 = malloc(0x70);
    void* p8 = malloc(0x70);
    void* p9 = malloc(0x70);
    void* p10 = malloc(0x70);
    void* p2 = malloc(0x70);
    
    free(p1); free(p3); free(p4); free(p5); free(p6);
    free(p7); free(p8); free(p9); free(p10);
    
    void* p12 = malloc(0x400);
}

调试观察:

  1. 多个 0x70 大小的 chunk 被 free 后进入 fastbins
  2. malloc(0x400) 触发 consolidate
  3. fastbins 中的 chunk 被合并并转移到 unsorted bin
  4. 合并后的 chunk 满足 malloc(0x400) 的需求

4. Unsafe Unlink 技术详解

4.1 Unlink 基本过程

Unlink 操作的核心代码:

FD = P->fd;
BK = P->bk;
FD->bk = BK;
BK->fd = FD;

4.2 利用原理

  1. 构造 fake chunk:

    • 设置 fd 和 bk 指针
    • 绕过安全检查(如 size 与 next chunk 的 prev_size 匹配)
  2. 通过 unlink 实现任意写:

    • 修改指针指向目标地址
    • 通过指针操作实现任意地址读写

4.3 简单示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

uint64_t *chunk0_ptr;

int main() {
    char b[8] = "aaaa";
    chunk0_ptr = &b;
    chunk0_ptr[0] = 0x4242424242424242LL;
    printf("%s\n", b);
}

这个简单示例展示了如何通过指针修改来改变内存内容,类似于 unlink 攻击后的效果。

5. 关键点总结

  1. Unsorted Bin 优先原则:非 fastbins 的 chunk 总是先进入 unsorted bin,只有在无法满足分配时才转移到其他 bins。

  2. Remainder Chunk:当从 unsorted bin 中切割分配时,剩余部分会成为 remainder chunk 保留在 unsorted bin 中。

  3. Consolidate 触发条件:分配大内存块时会触发 fastbins 的合并,合并后的 chunk 进入 unsorted bin。

  4. Unlink 攻击核心:通过伪造 chunk 的 fd 和 bk 指针,利用 unlink 操作实现任意地址写。

  5. 安全检查绕过:成功的 unlink 攻击需要精心构造 fake chunk 以通过 glibc 的安全检查。

How2Heap 问题解析与教学文档 1. 内存分配基础概念 1.1 Bin 的分类 在 glibc 的内存分配器中,free 后的 chunk 会根据大小被放入不同的 bin 中: fastbins : 用于小内存块的快速分配 (通常小于等于 0x80 字节) unsortedbin : 所有非 fastbins 的 chunk 被 free 后首先进入这里 smallbins : 用于中等大小的内存块 (通常小于 512 字节) largebins : 用于大内存块的分配 1.2 Unsorted Bin 的特殊性 Unsorted bin 有以下特点: 所有非 fastbins 大小的 chunk 被 free 后首先进入 unsorted bin 只有一个链表结构(不是复数形式) 在 malloc 时充当缓冲区角色 当无法满足分配请求时,会将 chunk 转移到合适的 smallbins 或 largebins 2. First Fit 分配策略分析 2.1 基础示例分析 调试观察: free(a) 后,512 字节的 chunk 进入 unsorted bin malloc(500) 时直接从 unsorted bin 中分配 2.2 Remainder Chunk 现象 修改示例: 观察: malloc(10) 从 unsorted bin 中切割出 0x20 字节 剩余 0x1f0 字节成为 remainder chunk 仍留在 unsorted bin malloc(512) 时 remainder chunk 不够大,从 top chunk 分配 remainder chunk 被转移到 smallbins 3. Consolidate 机制深入研究 3.1 极端示例分析 调试观察: 多个 0x70 大小的 chunk 被 free 后进入 fastbins malloc(0x400) 触发 consolidate fastbins 中的 chunk 被合并并转移到 unsorted bin 合并后的 chunk 满足 malloc(0x400) 的需求 4. Unsafe Unlink 技术详解 4.1 Unlink 基本过程 Unlink 操作的核心代码: 4.2 利用原理 构造 fake chunk: 设置 fd 和 bk 指针 绕过安全检查(如 size 与 next chunk 的 prev_ size 匹配) 通过 unlink 实现任意写: 修改指针指向目标地址 通过指针操作实现任意地址读写 4.3 简单示例 这个简单示例展示了如何通过指针修改来改变内存内容,类似于 unlink 攻击后的效果。 5. 关键点总结 Unsorted Bin 优先原则 :非 fastbins 的 chunk 总是先进入 unsorted bin,只有在无法满足分配时才转移到其他 bins。 Remainder Chunk :当从 unsorted bin 中切割分配时,剩余部分会成为 remainder chunk 保留在 unsorted bin 中。 Consolidate 触发条件 :分配大内存块时会触发 fastbins 的合并,合并后的 chunk 进入 unsorted bin。 Unlink 攻击核心 :通过伪造 chunk 的 fd 和 bk 指针,利用 unlink 操作实现任意地址写。 安全检查绕过 :成功的 unlink 攻击需要精心构造 fake chunk 以通过 glibc 的安全检查。