单字节延迟绑定实现rop
字数 1889 2025-08-29 08:30:06

单字节延迟绑定实现ROP攻击技术详解

1. 题目背景与保护措施分析

题目提供了一个有趣的挑战场景:在只能写入单个字节的情况下,利用延迟绑定机制实现完整的ROP攻击链,最终获取shell或实现ORW(Open-Read-Write)操作。

1.1 程序保护机制

  • 程序启用了常规保护措施
  • GOT表可写
  • 无RELRO保护(Partial或No RELRO)

1.2 程序关键特点

  • main函数中仅包含exit调用
  • 漏洞函数在init函数中被调用
  • init函数位于start函数中,在main函数之前执行

2. 漏洞利用基础:ret2dl_resolve技术

2.1 延迟绑定机制概述

当程序第一次调用动态链接函数时:

  1. 通过PLT表跳转到GOT表
  2. GOT表会寻找函数真实地址并回填
  3. 后续调用直接从PLT跳转到GOT再到真实地址

2.2 关键结构体

  • Dyn结构体:描述动态链接信息

    • d_tag:标记值,指明结构体类型
    • d_un:联合体,存储不同类型信息
  • Sym结构体:描述ELF符号信息

    • st_name:字符串表索引
    • st_info:符号类型信息
    • st_other:决定link_map参数有效性
    • st_value:符号地址偏移
  • Rel结构体:描述重定位信息

    • r_offset:加上link_map->l_addr等于GOT表地址
    • r_info:符号索引和类型信息
  • link_map结构体:存储目标函数查询结果

    • l_addr:目标函数所在lib的基址
    • l_info:Dyn结构体指针数组

2.3 _dl_fixup函数关键逻辑

if (__builtin_expect(ELFW(ST_VISIBILITY)(sym->st_other), 0) == 0) {
    // 重定位策略
}

2.4 攻击方式

  1. 改写.dynamic的DT_STRTAB(仅NO RELRO可行)

    • 修改.dynamic中字符串表指针到可控内存
    • 伪造函数名实现任意函数调用
  2. 操纵第二个参数指向伪造的Rel

    • 利用_dl_runtime_resolve无越界检查的特性
    • 伪造.rel.plt、.dynsym和.dynstr
    • 最终调用目标函数

3. 单字节利用技术详解

3.1 初始条件利用

  • 程序循环调用漏洞函数
  • write函数未被正确填写,每次都会执行延迟绑定
  • 通过单字节修改实现循环写入

3.2 改写exit GOT表

  1. 找到link_map相对于libc的偏移量

    • 位于ld文件中
    • 在_rtld_global中查找ns_loaded段
  2. 修改link_map->l_addr

    • 计算exit GOT表与write GOT表的偏移
    • 写入link_map偏移位置

3.3 泄露libc地址

  1. 修改stdout的flag字段和write指针

    • flag字段改为0xfbad3887
    • IO_write_ptr改为0xff
  2. 触发IO刷新

    • 修改l_info[DT_SYMTAB]的LSB指向DT_DEBUG
    • 在DT_DEBUG区域伪造"_IO_flush_all"字符串
  3. 关键步骤:

    # 修改l_info[DT_SYMTAB]指向DT_DEBUG
    write(l_info_DT_SYMTAB_addr, 0xB8)  # 单字节修改
    

3.4 伪造IO结构体

  1. 恢复write函数GOT表

    write(0x2C9338, 0x78)  # 恢复原始值
    
  2. 伪造IO_FILE结构体

    • 直接修改现有结构体
    • 设置vtable指针等关键字段
  3. 修改io_list_all指针

    • 指向可控堆块
    • 构造完整攻击链

4. 完整利用步骤

  1. 利用单字节写入修改link_map->l_addr
  2. 将write的解析重定向到exit
  3. 构造循环写入条件
  4. 修改l_info[DT_SYMTAB]指向DT_DEBUG
  5. 在DT_DEBUG区域伪造"_IO_flush_all"
  6. 设置stdout的flag和write指针
  7. 触发IO刷新泄露libc地址
  8. 恢复write函数GOT表
  9. 伪造IO_FILE结构体
  10. 修改io_list_all指针
  11. 最终获取shell或实现ORW

5. 关键调试技巧

  1. 查找link_map偏移:

    p/x ((struct r_debug *)0x7ffff7ffe118)->r_map
    p/x ((struct link_map *)0x7ffff7ffe2d0)->l_info[5]
    
  2. 查找DT_DEBUG地址:

    • 在.dynamic段中搜索d_tag为0x15的条目
  3. 验证修改效果:

    • 检查_dl_lookup_symbol_x函数的rdi参数
    • 确认解析的函数名是否正确

6. 防御措施

  1. 启用FULL RELRO保护
  2. 限制动态链接器的可写内存区域
  3. 对_dl_runtime_resolve添加边界检查
  4. 保护link_map关键数据结构

7. 扩展思考

  1. 在更严格保护下的利用可能性
  2. 其他单字节写入的利用场景
  3. 结合堆漏洞的复合利用方式
  4. 不同glibc版本间的差异处理

通过这种精妙的单字节利用技术,即使在极端受限的条件下,也能构建完整的攻击链,展示了二进制漏洞利用的艺术性和技术深度。

单字节延迟绑定实现ROP攻击技术详解 1. 题目背景与保护措施分析 题目提供了一个有趣的挑战场景:在只能写入 单个字节 的情况下,利用延迟绑定机制实现完整的ROP攻击链,最终获取shell或实现ORW(Open-Read-Write)操作。 1.1 程序保护机制 程序启用了常规保护措施 GOT表可写 无RELRO保护(Partial或No RELRO) 1.2 程序关键特点 main函数中仅包含exit调用 漏洞函数在init函数中被调用 init函数位于start函数中,在main函数之前执行 2. 漏洞利用基础:ret2dl_ resolve技术 2.1 延迟绑定机制概述 当程序第一次调用动态链接函数时: 通过PLT表跳转到GOT表 GOT表会寻找函数真实地址并回填 后续调用直接从PLT跳转到GOT再到真实地址 2.2 关键结构体 Dyn结构体 :描述动态链接信息 d_tag :标记值,指明结构体类型 d_un :联合体,存储不同类型信息 Sym结构体 :描述ELF符号信息 st_name :字符串表索引 st_info :符号类型信息 st_other :决定link_ map参数有效性 st_value :符号地址偏移 Rel结构体 :描述重定位信息 r_offset :加上link_ map->l_ addr等于GOT表地址 r_info :符号索引和类型信息 link_ map结构体 :存储目标函数查询结果 l_addr :目标函数所在lib的基址 l_info :Dyn结构体指针数组 2.3 _ dl_ fixup函数关键逻辑 2.4 攻击方式 改写.dynamic的DT_ STRTAB (仅NO RELRO可行) 修改.dynamic中字符串表指针到可控内存 伪造函数名实现任意函数调用 操纵第二个参数指向伪造的Rel 利用_ dl_ runtime_ resolve无越界检查的特性 伪造.rel.plt、.dynsym和.dynstr 最终调用目标函数 3. 单字节利用技术详解 3.1 初始条件利用 程序循环调用漏洞函数 write函数未被正确填写,每次都会执行延迟绑定 通过单字节修改实现循环写入 3.2 改写exit GOT表 找到link_ map相对于libc的偏移量 位于ld文件中 在_ rtld_ global中查找ns_ loaded段 修改link_ map->l_ addr 计算exit GOT表与write GOT表的偏移 写入link_ map偏移位置 3.3 泄露libc地址 修改stdout的flag字段和write指针 flag字段改为0xfbad3887 IO_ write_ ptr改为0xff 触发IO刷新 修改l_ info[ DT_ SYMTAB]的LSB指向DT_ DEBUG 在DT_ DEBUG区域伪造"_ IO_ flush_ all"字符串 关键步骤: 3.4 伪造IO结构体 恢复write函数GOT表 伪造IO_ FILE结构体 直接修改现有结构体 设置vtable指针等关键字段 修改io_ list_ all指针 指向可控堆块 构造完整攻击链 4. 完整利用步骤 利用单字节写入修改link_ map->l_ addr 将write的解析重定向到exit 构造循环写入条件 修改l_ info[ DT_ SYMTAB]指向DT_ DEBUG 在DT_ DEBUG区域伪造"_ IO_ flush_ all" 设置stdout的flag和write指针 触发IO刷新泄露libc地址 恢复write函数GOT表 伪造IO_ FILE结构体 修改io_ list_ all指针 最终获取shell或实现ORW 5. 关键调试技巧 查找link_ map偏移: 查找DT_ DEBUG地址: 在.dynamic段中搜索d_ tag为0x15的条目 验证修改效果: 检查_ dl_ lookup_ symbol_ x函数的rdi参数 确认解析的函数名是否正确 6. 防御措施 启用FULL RELRO保护 限制动态链接器的可写内存区域 对_ dl_ runtime_ resolve添加边界检查 保护link_ map关键数据结构 7. 扩展思考 在更严格保护下的利用可能性 其他单字节写入的利用场景 结合堆漏洞的复合利用方式 不同glibc版本间的差异处理 通过这种精妙的单字节利用技术,即使在极端受限的条件下,也能构建完整的攻击链,展示了二进制漏洞利用的艺术性和技术深度。