ROP发展

前身——return-to-libc

目的:

绕过DEP

主要思想:

代码重用攻击。利用进程空间中已经存在的代码,通过注入的异常数据控制其为攻击者服务。

新的利用点——复杂指令集CISC

CISC的问题:

代码中的一个字节的含义取决于上下文,原则上,任何一个字节都可能是一条指令的起始。

思想:

通过劫持控制流,攻击者可以令CPU按照其意愿重新解读已经存在的代码。

需求:

使用非常规的方式将短小指令片段串联成完整的代码流。
Galileo算法可为返回导向编程搜索可用的指令资源。

升级版——精简指令集RISC

对SPARC构造返回导向编程面临的问题:

无法利用意外的指令序列;X86下返回导向编程gadget的所有构造特点在RISC中都不存在。

新思路:

将函数的后缀作为gadget使用(利用结尾的ret-restore指令序列);利用结构化数据流使得gadget与SPARC的函数调用惯例相吻合;构造内存-内存gadget(寄存器仅在gadget内部使用)。

新防御——Smashing the gadgets:

核心思路:
阻止x86代码中出现以外的gadget。

手段一:抹掉0xC3字节(ret)
手段二:指令重新排序
手段三:寄存器压栈顺序随机化
手段四:寄存器重新分配

颠覆版——ROP without return

核心:

update-load-branch指令序列“pop x; jmp *x”
蹦床trampoline

函数调用步骤:

在esi中载入call-jmp序列的地址
在ebp中载入leave-jmp序列的地址
在eax中载入n+偏移量
将call-jmp序列的地址存储至地址n
改写esi,使其存储“返回地址”
esi值写入result位置后,再读出至edi
交换使返回值存入ebp,leave指令换入edi
在esi中载入pop-jmp序列的地址
在ecx中载入函数入口地址
在eax中载入地址n
交换esp和eax,栈指针指向n(函数地址)
edi处的leave指令将使函数“返回”

防御新思路——从结构上阻止程序控制流被劫持:

  • 程序控制流完整性保护(CFI)
  • 实用粗粒度CFI
    Springboard段--使得间接控制转移可以通过位校验进行检查,Springboard段内地址的第27位总是为0,且仅有Springboard段满足该条件。间接控制转移只能以Springboard段内的适当存根作为目标。
    缺陷:
    需要改写程序的二进制代码。很难识别出程序中所有合法控制转移目标,对二进制代码的修改困难且易错,兼容性问题在一定程度上依然存在。
  • 基于动态优化的CFI
    在程序执行过程中加以监视和约束。
    缺陷:
    效率太低。
  • 利用硬件特性和虚拟化技术的CFI
    利用虚拟化技术。
    内核模式下作为操作系统的一部分,性能开销低;提供了动态优化工具可能提供的CFI优势。
    监视目标:执行流由足够长的gadget序列组成。
    完整性检查的触发:
    设置滑动窗口,所有窗口外内存均设为不可执行。控制转移指向窗口外时,将触发异常并陷入内核,引起完整性检查;敏感系统调用也会引起完整性检查。
返回导向编程的基本流程:

始于对程序控制流的篡改(控制流异常)
各gadget由ret指令或pop-jump组合代替eip加以链接(大量控制流异常)
原始栈结构遭到破坏,ROP过程中栈指针单项移动(栈的行为异常)
有时,栈指针可能被篡改并指向不属于栈区的内存(栈的行为异常)

CFI基本思想:

通过预设的运行时校验,确保程序执行与预先定义的控制流图严格吻合;
通过对二进制码的静态分析来获取CFI所需保证的控制流图;
借由静态的二进制代码改写为程序添加运行时的自我校验。

CFI的基本安全性假设:

控制转移目标的标示符(ID)具有唯一性;
程序代码不可写;
程序数据不可执行。

CFI的搭建:
  • 内存访问控制 SMAC
    通过与运算,确保控制转移目标的最高位字节内容位40h;
    使得间接控制转移总是指向合法的代码区段;
    由此在一定程度上实现软件故障隔离(SFI)。

  • 受保护的影子栈
    专门划定内存区域用于检查ret指令是否响应了正确的call指令;
    为影子栈预设地址前缀,结合SMAC,可确保只有CFI的校验指令可以修改该区域。

CFI的弱点:

即使在静态分析中,间接控制转移的合法跳转目标也不唯一,不是排他的;
受到性能的制约,粗粒度化的CFI对控制流的约束更加松散。

改进型ROP——针对CFI

  • 利用以函数入口和函数调用点为起始的gadget
  • 图灵完全的改进型gadget集对抗现存最严格的CFI

改进型gadget的类型(主要来自kernel32.dll):
具有call指令前缀的gadget(主要);
call-ret配对的gadget组合;
“长nop"gadget。

绕过CFI不会导致返回导向编程的功能性有所缺损。

ROP变种“数据导向编程”——一切为了绕过CFI

特点:

通过污染数据(特别是指针)改变被重用代码的实际语义。借助循环不断注入新的攻击载荷,使得被重用代码的实际执行效果随之改变。

数据导向编程所重用的代码资源主要来自串操作。

交互式攻击 - 允许攻击者在每轮循环中输入不同的载荷以激活不同的gadget。

非交互式攻击 - 攻击者必须一次性输入整个攻击载荷,需要额外的指令元素以支持虚拟的跳转操作。

新防御——地址空间随机化ASLR

思想:

使gadget的位置变得无法确定。

粗粒度ASLR:

mmap offset、stack offset、brk offset随机化。


粗粒度的ASLR

粗粒度ASLR的改进:偏移量+内存区段的位置置换。

细粒度ASLR:

区段间----->区段内
改变代码文本的具体内容

实施

程序在加载时自我随机化;
通过虚拟机进行动态随机化;
操作系统的随机化。

ASLR的无效化:

场景1:攻击者无法披露目标程序的内存空间;
场景2:攻击者可以实施内存空间披露,但只能获得一个代码指针。
限制:对于任何ASLR,程序在执行时不在改变其内存空间结构。

“页面收割”最终暴露进程中的全部代码、API接口等可利用资源。

Just-In-Time代码重用

你可能感兴趣的:(ROP发展)