off by null低版本利用的两种方式
字数 1315 2025-08-22 12:22:48

Off by Null漏洞利用技术详解

1. 基本概念

1.1 Off by Null与Off by One的区别

  • Off by One: 允许覆盖一个字节,且可以控制该字节的内容
  • Off by Null: 只能覆盖一个字节,且该字节必须为NULL('\x00')

1.2 利用条件

Off by Null比Off by One利用条件更弱,需要更精巧的构造才能实现利用。

2. 低版本利用技术(glibc < 2.29)

2.1 可控pre_size的利用方式

2.1.1 原理分析

利用_int_free函数中的合并机制:

  1. 检查前一个chunk是否空闲(通过PREV_INUSE位)
  2. 如果空闲,则根据prev_size找到前一个chunk并进行合并(unlink)
  3. 检查后一个chunk是否空闲,如果空闲也进行合并

关键代码段:

if (!prev_inuse(p)) {
    prevsize = p->prev_size;
    size += prevsize;
    p = chunk_at_offset(p, -((long)prevsize));
    unlink(av, p, bck, fwd);
}

2.1.2 利用步骤

  1. 分配多个chunk,形成特定布局
  2. 释放特定chunk
  3. 利用Off by Null修改下一个chunk的size和prev_size
  4. 触发合并操作,制造堆块重叠

2.1.3 示例代码分析

# 分配初始堆块
add(0, 0x200)  # chunk0
add(1, 0x18)   # chunk1
add(2, 0x1f0)  # chunk2
add(3, 0x10)   # chunk3 (防止合并)

# 释放chunk0
free(0)

# 利用Off by Null修改chunk2的size和prev_size
# 填充chunk1的数据区,覆盖chunk2的头部
edit(1, b'a'*0x10 + p64(0x230) + p8(0))

# 释放chunk2,触发合并
free(2)

2.2 不可控pre_size的利用方式

2.2.1 原理分析

当无法控制prev_size时,通过修改size字段的低字节为NULL来改变chunk大小,然后通过精心设计的堆布局实现利用。

2.2.2 利用步骤

  1. 分配多个chunk形成特定布局
  2. 释放中间chunk
  3. 利用Off by Null修改下一个chunk的size字段
  4. 重新分配chunk进行切割
  5. 通过多次释放触发合并,制造堆块重叠

2.2.3 示例代码分析

# 初始堆布局
add(0, 0x18)   # chunk0
add(1, 0x408)  # chunk1
add(2, 0x2f0)  # chunk2
add(3, 0x20)   # chunk3 (防止合并)

# 释放chunk1
free(1)

# 利用Off by Null修改chunk1的size字段
edit(0, b'a'*0x18 + p8(0))  # 0x410 -> 0x400

# 重新分配进行切割
add(4, 0x1f0)  # 从chunk1切割
add(5, 0x10)   # 分割块
add(6, 0x1f0 - 0x40)  # 从剩余空间切割
add(7, 0x10)   # 分割块

# 触发合并
free(4)
free(2)
free(6)  # 此时产生堆块重叠

3. 高版本利用技术(glibc ≥ 2.29)

3.1 新版本保护机制

glibc 2.29引入了prev_size的检查:

if (__glibc_unlikely(chunksize(p) != prevsize))
    malloc_printerr("corrupted size vs. prev_size while consolidating");

3.2 利用思路

  1. House of Einherjar: 通过伪造fake chunk并利用Off by Null修改PREV_INUSE位
  2. Unlink攻击: 需要泄露堆地址,精心构造fd和bk指针绕过检查
  3. Tcache Poisoning: 结合tcache机制进行利用

4. 防御措施

  1. 输入长度严格检查,避免溢出
  2. 使用现代glibc版本(≥2.29)
  3. 启用堆保护机制(如FORTIFY_SOURCE)

5. 总结

版本 利用方式 关键点 限制条件
低版本 可控pre_size 伪造prev_size触发合并 需要控制prev_size
低版本 不可控pre_size 修改size字段进行切割 需要复杂堆布局
高版本 House of Einherjar 伪造fake chunk 需要地址泄露
高版本 Unlink攻击 精心构造fd/bk 需要堆地址

掌握Off by Null的利用技术需要深入理解glibc堆管理机制,特别是合并操作的细节。不同版本的glibc有不同的保护机制,需要针对性地调整利用方式。

Off by Null漏洞利用技术详解 1. 基本概念 1.1 Off by Null与Off by One的区别 Off by One : 允许覆盖一个字节,且可以控制该字节的内容 Off by Null : 只能覆盖一个字节,且该字节必须为NULL('\x00') 1.2 利用条件 Off by Null比Off by One利用条件更弱,需要更精巧的构造才能实现利用。 2. 低版本利用技术(glibc < 2.29) 2.1 可控pre_ size的利用方式 2.1.1 原理分析 利用 _int_free 函数中的合并机制: 检查前一个chunk是否空闲(通过PREV_ INUSE位) 如果空闲,则根据prev_ size找到前一个chunk并进行合并(unlink) 检查后一个chunk是否空闲,如果空闲也进行合并 关键代码段: 2.1.2 利用步骤 分配多个chunk,形成特定布局 释放特定chunk 利用Off by Null修改下一个chunk的size和prev_ size 触发合并操作,制造堆块重叠 2.1.3 示例代码分析 2.2 不可控pre_ size的利用方式 2.2.1 原理分析 当无法控制prev_ size时,通过修改size字段的低字节为NULL来改变chunk大小,然后通过精心设计的堆布局实现利用。 2.2.2 利用步骤 分配多个chunk形成特定布局 释放中间chunk 利用Off by Null修改下一个chunk的size字段 重新分配chunk进行切割 通过多次释放触发合并,制造堆块重叠 2.2.3 示例代码分析 3. 高版本利用技术(glibc ≥ 2.29) 3.1 新版本保护机制 glibc 2.29引入了prev_ size的检查: 3.2 利用思路 House of Einherjar : 通过伪造fake chunk并利用Off by Null修改PREV_ INUSE位 Unlink攻击 : 需要泄露堆地址,精心构造fd和bk指针绕过检查 Tcache Poisoning : 结合tcache机制进行利用 4. 防御措施 输入长度严格检查,避免溢出 使用现代glibc版本(≥2.29) 启用堆保护机制(如FORTIFY_ SOURCE) 5. 总结 | 版本 | 利用方式 | 关键点 | 限制条件 | |------|----------|--------|----------| | 低版本 | 可控pre_ size | 伪造prev_ size触发合并 | 需要控制prev_ size | | 低版本 | 不可控pre_ size | 修改size字段进行切割 | 需要复杂堆布局 | | 高版本 | House of Einherjar | 伪造fake chunk | 需要地址泄露 | | 高版本 | Unlink攻击 | 精心构造fd/bk | 需要堆地址 | 掌握Off by Null的利用技术需要深入理解glibc堆管理机制,特别是合并操作的细节。不同版本的glibc有不同的保护机制,需要针对性地调整利用方式。