面向返回的编程(ROP)
面向返回的编程(ROP) 是什么?
面向返回的编程(ROP)ROP 是一种代码复用利用技术,通过把以 RET 结尾的短指令序列(gadget)串成链来执行任意计算,而无需注入新代码。
Hovav Shacham 在 2007 年论文《The Geometry of Innocent Flesh on the Bone》中提出 ROP,证明 return-into-libc 可以推广为图灵完备的计算,从而击败 DEP/W^X。攻击者破坏栈,并写入一串地址,每个地址指向一个短小的 gadget——以 RET 结尾的几条指令。每个 gadget 执行后,RET 弹出下一个地址,于是控制流在已有的可执行字节(libc、程序本体、各类库)之间流动,不存在任何可被 DEP 拦截的注入代码。
由于每个 gadget 地址都是绝对地址,ROP 依赖于知道代码在内存中的位置,而这正是 ASLR 所随机化的,因此真实利用往往与信息泄露配合使用。其变体推广了这一原语:JOP(跳转)与 COP(调用)串联间接跳转/调用而非返回,SROP(sigreturn)则滥用内核的信号帧恢复,一次性设置所有寄存器。Blind ROP(Bittau 等,2014)甚至能在没有二进制文件的情况下,通过观察崩溃对远程服务构造利用链。
ROP 是整整一代缓解措施诞生的主因。防御针对三个面之一:gadget 可用性、控制流完整性,或在源头保证内存安全。Intel CET(自 Tiger Lake,2020 年起)强制使用硬件影子栈来检测被篡改的返回地址,并以 间接分支跟踪(endbr64)对抗 JOP/COP;ARM 提供 Pointer Authentication 与 BTI。Rust 等内存安全语言则从根本上消除了引发利用链的破坏性缺陷。
flowchart TD A["内存破坏缺陷<br/>栈溢出"] --> B["覆盖保存的返回地址"] B --> C["栈中现在是<br/>gadget 地址链"] C --> G1["Gadget 1: pop rdi, ret"] G1 --> G2["Gadget 2: pop rsi, ret"] G2 --> G3["Gadget 3: syscall, ret"] G3 --> X["execve /bin/sh"] D1["DEP: 栈不可执行"] -. 被代码复用绕过 .-> C D2["ASLR"] -. 需要信息泄露 .-> C D3["Intel CET 影子栈"] -. 阻止非法 RET .-> G1
● 示例
- 01
利用 glibc 中的 pop-rdi/syscall gadget 链调用 execve("/bin/sh")。
- 02
通过 KASLR 信息泄露和 ROP 进入 commit_creds(prepare_kernel_cred(0)) 提权。
● 常见问题
面向返回的编程(ROP) 是什么?
ROP 是一种代码复用利用技术,通过把以 RET 结尾的短指令序列(gadget)串成链来执行任意计算,而无需注入新代码。 它属于网络安全的 应用安全 分类。
面向返回的编程(ROP) 是什么意思?
ROP 是一种代码复用利用技术,通过把以 RET 结尾的短指令序列(gadget)串成链来执行任意计算,而无需注入新代码。
如何防御 面向返回的编程(ROP)?
针对 面向返回的编程(ROP) 的防御通常结合技术控制与运营实践,详见上方完整定义。
面向返回的编程(ROP) 还有哪些其他名称?
常见的别称包括: ROP, 代码复用攻击, Return-to-libc。