finish 8.1

This commit is contained in:
firmianay 2018-03-19 20:12:48 +08:00
parent 831859c086
commit 61bd597119
3 changed files with 50 additions and 0 deletions

View File

@ -19,6 +19,19 @@
所以其实这些早期的防御技术都默认了一个前提,即 ROP 中必定存在 return 指令。 所以其实这些早期的防御技术都默认了一个前提,即 ROP 中必定存在 return 指令。
另外对于重写二进制文件消除 return 指令的技术,根据二进制偏移也可能会得到攻击者需要的非预期指令,比如下面这段指令:
```
b8 13 00 00 00 mov $0x13, %eax
e9 c3 f8 ff ff jmp 3aae9
```
偏移两个十六进制得到下面这样:
```
00 00 add %al, (%eax)
00 e9 add %ch, %cl
c3 ret
```
最终还是出现了 return 指令。
## 没有 return 的 ROP ## 没有 return 的 ROP
后来又有人提出了不依赖于 return 指令的 ROP使得早期的防御技术完全失效。return 指令的作用主要有两个:第一通过间接跳转改变执行流,第二是更新寄存器状态。在 x86 和 ARM 中都存在一些指令序列,也能够完成这些工作,它们首先更新全局状态(如栈指针),然后根据更新后的状态加载下一条指令序列的地址,最后跳转过去执行(把它叫做 update-load-branch 指令序列)。这样就避免的 return 指令的使用。 后来又有人提出了不依赖于 return 指令的 ROP使得早期的防御技术完全失效。return 指令的作用主要有两个:第一通过间接跳转改变执行流,第二是更新寄存器状态。在 x86 和 ARM 中都存在一些指令序列,也能够完成这些工作,它们首先更新全局状态(如栈指针),然后根据更新后的状态加载下一条指令序列的地址,最后跳转过去执行(把它叫做 update-load-branch 指令序列)。这样就避免的 return 指令的使用。

View File

@ -1 +1,38 @@
# 8.1 The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86) # 8.1 The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86)
## 简介
论文提出了一种 return-into-libc 的攻击方法以对抗针对传统代码注入攻击的防御技术W⊕X。它不会调用到完整的函数而是通过将一些被称作 gadgets 的指令片段组合在一起形成指令序列以达到任意代码执行的效果。这一技术为返回导向编程Return-Oriented Programming奠定了基础。
## 背景
对于一个攻击者,它要完成的任务有两个:
1. 首先它必须找到某种方法来改变程序的执行流
2. 然后让程序执行攻击者希望的操作
在传统的栈溢出攻击里攻击者通过溢出改写返回地址来改变程序执行流将指针指向攻击者注入的代码shellcode整个攻击过程就完成了。
后来很多针对性的防御技术被提出来,其中 W⊕X 将内存标记为可写W或可执行X但不可以同时兼有这样的结果是要么攻击者的代码注入不了要么即使攻击者在可写的内存中注入了代码也不可以执行它。
那既然代码注入不可行,一种思路是利用内存中已有的程序代码,来达到攻击的目的。由于标准 C 库几乎在每个 Linux 程序执行时都会被加载,攻击者就开始考虑利用 libc 中的函数,这种技术就是最初版本的 return-into-libc。理论上来说通过在栈上布置参数即可调用任意程序在 text 段上和 libc 中的任意函数。
那么 W⊕X 对 return-into-libc 的影响是什么呢?主要有下面两点:
1. 在 return-into-libc 攻击中,攻击者可以一个接一个地调用 libc 中的函数,但这个执行流仍然是线性的,而不像代码注入那样可以执行任意代码。
2. 攻击者只能使用程序 text 段中已有的和 libc 中加载的函数,通过移除这些特定的函数即可对攻击者加以限制。
在这样的背景下,本论文就提出了一种新型的 return-into-libc 攻击方法。这种方法可以执行任意代码,而且不需要调用到任何函数。
## 寻找指令序列
为了完成指令序列的构建,首先需要在 libc 中找到一些以 return 指令结尾,并且在执行时必然以 return 结束而不会跳到其它地方的小工具gadgets算法如下
![](../pic/8.1_galileo.png)
大概就是扫描二进制找到 ret 指令,将其作为 trie 的根节点,然后回溯解析前面的指令,如果是有效指令,将其添加为子节点,再判断是否为 boring如果不是就继续递归回溯。举个例子在一个 trie 中一个表示 `pop %eax` 的节点是表示 `ret` 的根节点的子节点,则这个 gadgets 为 `pop %eax; ret`。如此就能把有用的 gadgets 都找出来。
那么哪些指令是 boring 的呢?
1. 该指令是 `leave`,并且后跟一个 `ret` 指令
2. 或者该指令是一个 `pop %ebp`,并且后跟一个 `ret` 指令
3. 或者该指令是返回或者非条件跳转
找到这些 gadgets 之后,就可以根据需要将它们串起来形成 ROP 链,执行任意代码了。

BIN
pic/8.1_galileo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB