施可荣 | 代码复用攻击
KaMer | BUUCTF easyre & xor
代码复用攻击
1.面向返回编程( ROP )攻击
返回到系统库函数( ret - to - libc )是最早的 ROP 攻击"。这种方法可以绕过数据执行保护( DEP ),在不注入恶意代码的情况下,通过修改返回地址,跳转到并执行 libc (包含各种共享函数的 C 语言库)中的某个函数。例如:跳转到库函数 system (),并提供参数“/ bin / sh ”,衍生一个 shell 。虽然返回到系统库函数攻击突破了数据执行保护( DEP )的限制,但 libc 中可用的函数功能有限,限制了这种方式的攻击能力。
为了突破返回到系统库函数攻击的限制, Shacham 等人在2007年提出 ROP 攻击。这种攻击复用的代码片段以 ret 指令或具有类似功能的指令序列(例如:pop x ; jmp * x )结尾。ret 之前指令实现攻击者选择实现的功能, ret 指令则将控制流转换到下一个代码片段,这种方式使攻击者复用现有代码构造复杂攻击。
目前 ROP 攻击是漏洞利用的重要技术之一,攻击者可利用 ROP 攻击先关闭 DEP ,然后注入并执行恶意代码。图1所示为 ROP 攻击的例子。在第1步,攻击者将攻击负载载入到应用的堆栈中。负载为 线框中的内容,包括一定数量的返回地址与相关参数。在第2步,攻击者利用存储错误,用代码片段 A 的地址覆盖栈中返回地址。从第3步开始,攻 已经挟持控制流,将制流重定向到代码片段 A 。代码片段 A 改变栈指针(在x86架构中栈指针为 esp )指向载入的攻击负载。此时, esp 代替 eip 作为程序指针,这为第4步。从第5步开始,通过执行 ret 指令,将控制流从一个代码片段转移到下一个代码片段,本例最后执行一个系统调用。从上例可以看出, ROP 的基本块为不改变 esp 的代码块,条件分支与循环可以通过修改 esp 实现。综合使用算术运算、逻辑运算与条件分支可以实现图灵完备的攻击。
2.面向跳转编程( JOP )攻击
因为 ROP 攻击依赖于返回指令,很容易根据这一特征进行检测并防御,例如:检测指令流中频繁使用返回指令,或利用编译器消除可执行文件中的返回指令。为了改变这一不足, Bletsch 等提出 JOP 攻击”。与 ROP 攻击类似, JOP 攻击也是将较短的代码片段串连执行实现,只是复用的代码片段由间接跳转指令 jmp 结尾。JOP 攻击利用派发表( dispatch table )保存被复用代码片段地址与参数,利用任意指向派发表的寄存器作为程序计数器,由特定的派发代码片段( dispatcher )挟持控制流。在调用下一个复用代码片段时,派发代码片段设定虚拟程序计数器,跳转到相应代码片段。
图2所示为 JOP 攻击示例。与 ROP 攻击类似, JOP 攻击也需将攻击负载载入到内存中,攻击负载为图中所示的派发表,包含可复用代码的起始地址及相关数据。在发起攻击之前,将派发表的起始地址保存到寄存器 edx 中(即虚拟程序计数器),派发代码片段利用一条加法指令驱动控制流。由此可见, JOP 攻击不依赖于程序栈和 esp 引用被复用的代码片段,可以用任意的,甚至不连续的存储区间保存派发表。
3.面向伪造对象编程(CO0P)攻击
CO0P攻击是一种顶级的针对前向控制流完整性( CFI )的攻击方式,目前主要出现在学术界,还没有出现在漏洞利用的工具包中。Schuster 等证明CO0P攻击可攻破Win7上的E10,以及64位 Linux 上的 Firefox 。Matt 等则用这种攻击方式成功绕过微软执行流保护( CFG )对 Win 10 Edge 的保
护。
为了绕过前向 CFI 检查, COOP 攻击复用 C ++对象中的虚数。每个虚函数实现一定的功能(例如:实现算术运算,载入值到寄存器等),把这些虚函数组合在一起实现复杂的任务。每个复用的虚函数称为虚函数片段( virtual function gadget , vfgad - get ),其中最重要的 vfgadget 是主循环函数( ML - G )。主循环函数中包含一个指针数组或链表,可用于将伪造对象组合在一起,然后在主循环函数中按攻击者的意图依次调用 vfgadget 。
COOP 攻击的控制流程如图3所示。COOP 攻击开始时挟持目标应用中的 C ++对象,这个对象称为初始化对象。初始化对象的虚指针指向一个包含主循环函数指针的虚表。攻击者通过控制的初始化对象调用一个虚函数启动主循环函数。通过在主循环函数中迭代对象数组或链表(包含伪造对象指针),调用攻击者指定的 vfgadget 。由此可见, COOP 攻击也与 ROP 攻击类似, ROP 攻击在控制程序指针后先操作栈指针,然后连续执行一系列的以返回指令结尾的代码片段,而CO0P在控制程序指针后进入一个 环函数,依靠循环函数依次执行攻击者精心伪造的虚函数。
BUUCTFeasyre
例行查壳,发现有壳
脱壳
Ida打开
从if语句可知flag为ACTF{}中的字符,for循环是要从_data_start字符串中查找v4。
构建exp
byte_402000 = '~}|{zyxwvutsrqponmlkjihgfedcba`_^][ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !"'
v4 = [42,70,39,34,78,44,34,40,73,63,43,64]
flag = ''
for i in v4:
flag += chr(byte_402000.find(chr(i)) + 1)
print(flag)
BUUCTFxor
例行查壳,发现无壳。
ida64打开,进行反编译
查看global字符串
从第13,15行代码可知flag长度为33
提取"inputyour flag:n"里面的值
运算规则: v6[i]=globa[i]^global[i-1]
构建exp
str = [
0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11,
0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F,
0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F,
0x47, 0x32, 0x4F, 0x00]
flag = chr(str[0])
i = 1
while True:
if i<len(str):
flag +=chr(str[i] ^ str[i-1])
i +=1
else:
break
print(flag)
原文始发于微信公众号(火炬木攻防实验室):代码复用攻击 & BUUCTF
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论