ret2resolve深入分析—以x86、x64视角
字数 1980 2025-08-24 07:48:34
ret2resolve技术深入分析 - x86与x64架构视角
基本概念
ret2resolve是一种利用动态链接机制中延迟绑定特性的攻击技术。让我们通过一个简单例子来理解基本概念:
#include <stdio.h>
int main() {
puts("Hello Pwn\n");
return 0;
}
// 编译命令: gcc -m32 -fno-stack-protector -no-pie -s hellopwn.c
动态链接关键机制
- 延迟绑定(Lazy Binding): 函数在第一次调用时才进行解析和绑定
- _dl_runtime_resolve: 负责解析函数地址的核心例程,签名:
_dl_runtime_resolve(link_map, reloc_arg)
关键数据结构
1. .dynamic节区
包含动态链接需要的信息,重点关注三项:
- DT_STRTAB: 指向.dynstr节区
- DT_SYMTAB: 指向.dynsym节区
- DT_JMPREL: 指向.rel.plt节区
2. .dynstr节区
字符串表,包含动态链接用到的字符串(包括函数名),每个以0结尾。
3. .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;
4. .rel.plt节区
重定位表(结构体数组),每个结构体对应一个导入函数:
typedef struct {
Elf32_Addr r_offset; // 指向GOT表的指针
Elf32_Word r_info; // 符号在.dynsym中的下标(右移8位)
} Elf32_Rel;
_dl_runtime_resolve工作流程
- 访问.dynamic,获取.dynsym、.dynstr、.rel.plt指针
.rel.plt + reloc_arg获取当前函数的重定位表项指针(rel)rel->r_info >> 8作为.dynsym下标,获取符号表项指针(sym).dynstr + sym->st_name得到符号名字符串指针- 在动态库中查找函数地址,写入
*rel->r_offset(GOT表) - 调用该函数
x86架构利用技术
利用方式1:修改.dynamic节区(No RELRO)
适用条件: .dynamic节区可写(No RELRO保护)
攻击思路:
- 修改.dynamic中的.dynstr指针,指向可控区域
- 在可控区域伪造函数名字符串(如将"free"改为"system")
- 触发目标函数调用
示例攻击步骤:
- 在bss段伪造.dynstr结构
- 计算free和system字符串的偏移差异
- 通过堆溢出修改.dynamic中的strtab指针
- 触发free调用实际执行system
利用方式2:控制reloc_arg(Partial RELRO)
适用条件: .dynamic不可写(Partial RELRO)
攻击思路:
- 控制_dl_runtime_resolve的reloc_arg参数
- 使.rel.plt + reloc_arg指向可控区域
- 伪造重定位表项(Elf32_Rel)
- 通过r_info控制符号表项
- 伪造符号名字符串
关键技术点:
- 伪造的r_info构造:
(index << 8) | 0x7,其中index是伪造符号表项的下标 - 符号表项对齐: Elf32_Sym结构体大小为0x10,需要对齐
- st_name计算: 伪造字符串地址 - .dynstr基址
完整攻击链:
- 栈迁移到bss段
- 第一次read: 将payload写入bss
- 构造伪造的rel和sym结构
- 调用plt[0]触发_dl_runtime_resolve
- 通过伪造结构最终执行system("/bin/sh")
x64架构利用技术
x64架构利用原理与x86类似,但有以下差异:
- 参数通过寄存器传递,不需要栈迁移
- 可利用的ROP gadget更多样
- 结构体大小和对齐方式不同
典型攻击步骤:
- 第一次read: 将"/bin/sh"和伪造的.dynstr写入bss
- 第二次read: 修改.dynamic中的dynstr指针
- 调用plt[0]触发_dl_fixup
- 通过伪造的dynstr使解析结果为system
关键点:
- plt[0]调用后的参数1是link_map,参数2(reloc_arg)需要控制
- 对于已解析过的函数,需要重新触发解析过程
防御与绕过
常见防御机制
- Full RELRO: 使.dynamic节区只读
- 栈保护(Stack Canary)
- ASLR
可能的绕过方式
- 信息泄露结合ret2resolve
- 利用其他可写区域伪造结构
- 多阶段攻击组合
总结
ret2resolve技术通过操纵动态链接过程中的数据结构,实现在不知道libc地址的情况下完成攻击。理解这项技术需要深入掌握ELF文件格式和动态链接机制,特别是:
- .dynamic、.dynstr、.dynsym、.rel.plt等节区的结构和关系
- _dl_runtime_resolve的工作流程
- 如何构造伪造的数据结构来"欺骗"动态链接器
这项技术在CTF比赛中常见于没有信息泄露但存在溢出漏洞的题目中,是二进制漏洞利用中的重要技术之一。