Chapter 11 Windows系统安全机制及漏洞防护技术
11.1 DEP
DEP(Data Execution Protection/NX):禁用栈和堆区的代码执行,能够有效防止shellcode在栈和堆上执行
但会带来一定的兼容性和灵活性问题:如用于提取其他软件窗口上文字的软件,可能需要在栈或堆中执行代码,DEP启用后这类软件可能无法正常运行。
支持架构:Intel、AMD等
实现原理:将栈和堆的访问权限(属性)设置为NX
Windows选项:
- Optin:DEP仅用于系统服务与进程(个人版默认)
- Optout:排除列表程序外的所有程序启用(服务器版默认)
- AlwaysOn:所有进程全部启用
- AlwaysOff:所有进程全部禁用
绕过思路:Ret2Libc、ROP、JOP、COP等
11.2 栈溢出检查——GS
在所有函数栈帧高处放置一个Stack Guard(Windows中称为Stack Cookie,Linux中称为Canary),这是一个随机数,且可检验其是否改变。函数结束后会检查此处的值是否被修改。可以在一定程度上防范栈溢出。
- 以.data节的第一个DWORD作为其种子,称为原始Cookie,所有函数的Cookie均使用这个种子生成。
- 栈帧初始化后以ESP异或种子作为cookie使用,能够提升其随机性。
- 函数返回前使用esp还原出种子
- 调用Security_check_cookie函数进行校验。
当满足以下情况时不使用此种保护:
- 函数无缓冲区
- 函数被定义为具有变量参数列表(即可变参数)
- 函数使用无保护的关键字标记
- 函数第一条语句中含内嵌汇编代码
- 缓冲区不是8字节类型且不大于4字节
使用#param strict_gs_check(on)选项可以强制对任意类型函数添加cookie
变量重排技术:将字符串变量移动到栈帧的高地址,即紧靠cookie的位置,这样一旦发生溢出能够立即发现,无论溢出多少字节。如果字符串变量距离cookie有一段距离,那么其溢出有限字节可能不会被cookie发现。
无法防御:
- 未被保护的函数
- 改写函数指针类攻击
- 异常处理类攻击
- 堆溢出攻击
- 其他(如能够利用其他漏洞泄露cookie的值)
绕过方法:
- 利用未被保护的函数
- 覆盖C++虚函数指针
- 攻击异常处理机制
- 同时替换栈和data中的cookie
11.3 ASLR
地址空间布局随机化,使栈和堆的基址在加载时随机确定、程序自身和关联库的基址在加载时也随机确定
不足:
- 需要和DEP配合使用。否则恶意代码可以通过程序进程表结构获取DLL加载基址
- ASLR的随机性较小(仅针对32位windows系统,32位/64位linux系统有更好的随机性)
- 兼容性问题(一些老处理器不支持等问题)
- 地址部分覆盖(对于windows 32位系统只能控制程序地址随机化后两个字节,前两个字节不变,对于Linux系统则是最低12位不变,因为内存需要4KB对齐)
11.4 SafeSEH
保护、检测和防止堆栈中的SEH函数指针被覆盖的技术
- 检查异常处理程序是否位于栈中
- 如果异常处理程序指针不是栈中地址,会再次检查是否属于一个Image的地址空间(mmap映射机制,不做要求)
11.5 EMET
Enhanced Mitigation Experience Toolkit,含DEP、ASLR、SEHOP等防护措施
- SEHOP:结构化异常处理覆写保护,对抗覆盖SEH攻击
- EAF:导出表地址过滤:禁止shellcode搜索API地址
- HeapSpray Allocations:将所有有可能被堆喷射的常见内存地址首先分配掉
- Null Page Allocation:使用提前占位的方式将空指针未初始化之前默认指向的地址首先分配掉
练习题:
1. 分析如下代码片段,回答下列问题:(29分)
1 | void foo(){ |
注:上述代码已开启Stack Cookie保护,未开启ASLR保护。
(1) 这段代码中存在的漏洞是________________________。(2分)
(2) 能否直接输入很多字符产生栈溢出?__________ ,简述Stack Cookie如何防止这一类栈溢出:___________________________________________________________________________________________________ (4分)
(3) 虽然我们不能直接进行栈溢出,但因为有____________漏洞的存在,使我们有可能_______________________________,从而绕过Stack Cookie的防护。注意,本程序没有开启ASLR防护,因此我们可以获取到_______________。请简述你的利用思路及这样利用能够成功的原因:________________________________________________________________________________,在这种绕过方式中,Stack cookie应作为printf的第___个参数输出。(10分)
(4) 这个函数的利用可能需要输入两次,在第一次输入后,你成功让这个函数又从头开始执行了一次,这样你就可以再一次进行输入。假设你第一次输入获取到的stack cookie为0xdeadbeef,函数第一次刚开始执行时esp=0x7f773484,则函数第二次执行时的stack cookie值应为 ____________(Stack cookie的生成方式即为GS栈溢出保护中的生成方式)(5分)
答案:
(1) 格式化字符串漏洞、栈溢出漏洞
(2) 不能;Stack cookie是一个随机数,置于函数栈帧的高地址端,栈溢出发生时可能会覆盖Stack cookie,在函数返回时对Stack cookie进行检查,若发现被修改,则会直接报错退出程序
(3) 格式化字符串漏洞;泄露Stack cookie的值;foo函数的起始地址;利用格式化字符串漏洞打印出Stack cookie的值(%x)及修改返回地址(%n);10
(4) 0xdeadbeeb