这是《【软件与系统安全】笔记与期末复习》系列中的一篇
虽然对缓冲区溢出的认知已超过 40 年之久, 但缓冲区溢出仍未被消除。部分原因在于存在大量的利用选项:
防御可以在不同的时机进行
是栈溢出的检测机制, 又称“栈 cookies”,由 gcc 的 StackGuard 实现
原理:将一个 dummy 值(或随机值)写到栈上的返回地址之前,并在函数返回时检查该值。不小心构造的栈溢出(假定是顺序栈粉碎)会覆写该“canary”单元, 该行为将被探测到。
对 canary 单元, 用正确的值覆写
无法抵御 disclosure 攻击是 StackGuard 的最大局限性
disclosure 攻击通过对缓冲区的“overread”实现
著名例子: 对 SSL 的 Heartbleed 攻击
以下程序为什么会对 Stackguard 的 canaries 造成威胁?
char packet[10];
…
// suppose len is adversary controlled
strncpy(buf, packet, len);
send(fd, buf, len);
有时不需要覆写返回地址, 可以溢出:
void foo () {...}
void bar () {...}
int main() {
char buf [16];
void (*f) () = &foo;
gets(buf);
f();
}
假定我们没有机会溢出返回地址
可溢出缓冲区, 使得函数指针被修改为 bar 的地址, 然后函数调用将调用 bar 而非 foo
劫持函数指针的其他方法
有时不需要覆写返回地址, 可以溢出:
安全敏感的局部变量
堆数据
全局数据
· · ·
如何防御?
也是一种运行时检测方法, 可以看作StackGuard的扩展
在一个进程地址空间中关键内存区域之间放置守卫页 (像一些gaps)
效果: 能失效缓冲区溢出攻击, 特别是对全局数据区的溢出攻击
甚至可以在栈帧之间、或者堆缓冲区之间放置守卫页
冯诺依曼体系结构
哈佛架构
Data Execution Prevention (数据执行保护): 是一种运行时缓解技术
DEP又称作Nx-bit (non executable bit), W⊕X
能够阻止代码注入攻击
很多缓冲区溢出攻击涉及将机器码复制到目标缓冲区, 然后将执行转移到这些缓冲区
DEP 被绝大多数操作系统和指令集体系结构支持
对 Nx-bit 的不同叫法
如果CPU硬件支持, DEP可作为操作系统更新, 通过更改对进程虚拟地址空间的内存管理, 提供对现有漏洞程序的保护
DEP将栈和堆置为不可执行, 对多种缓冲区溢出攻击提供了一种高度的保护
但有一些合法程序需要将可执行代码放在栈上:
思路: 重用程序自身的代码
Return-to-libc: 用危险的库函数的地址替换返回地址
危险库函数如 system()
攻击者构造合适的参数(在栈上, 返回指令指针的上方)
函数返回,库函数得到执行
execve(“/bin/sh”)
甚至可以链接两个库函数调用
具体地
攻击者用一个溢出填充buffer:
当被攻击的函数返回时, 恢复(更改过的)ebp, 然后pop更改后的返回地址到eip, 从而开始执行库函数代码
因为库函数相信它已被调用, 故会将栈顶当前值(占位符)作为它自己栈帧的返回指令指针, 之上是参数
最终会在占位符位置的下方创建起一个新的栈帧 (对应于库函数的执行)
根据库函数参数类型以及库函数对参数的解释方式, 攻击者可能需要准确地知道参数地址以做溢出写
代码重用与代码注入的协同
在很多攻击中, 代码重用攻击用来作为禁用DEP的第一步
目标是允许对栈内存进行执行
有一个系统调用可以更改栈的读/写/执行属性
设置对于起始于addr的内存区域的保护
调用此系统调用, 允许在栈上的“执行”属性, 然后开始执行被注入的代码
面向返回的编程
正常机器指令序列
ROP执行
TODO
Turing completeness
一种语言是Turing complete的,如果其具有
这两点在ROP中均能实现
ROP的工作基于对程序控制流的修改
控制流完整性 (Control-flow integrity, CFI)
预先决定被攻击程序的控制流图
向该程序中插入检测, 使得在程序运行时发生非法控制流跳转时,终止程序
ROP利用要求攻击者对代码/数据地址的知识,例如
思路: 引入人为的多样性(随机化)
有很多方法能够实现随机化
实现随机化的时机
地址空间随机化的挑战
地址空间随机化的有效性取决于
ASLR(Address space layout randomization)
对于位置无关的可执行程序(PIE), 随机化该可执行程序的基地址
关注的是内存块的随机化
ASLR 是一种粗粒度的随机化形式
攻破 ASLR 的方法
如果随机地址空间很小, 可以进行一个穷举搜索
ASLR 经常被 memory disclosure (内存泄漏) 攻破
费根检查(fagan inspection)
检查表
危险的 C 库函数
所有输入都是恶意的
最小化攻击面
识别攻击面