栈缓冲区溢出之二 ASLR

发布日期:2019年02月19日 类别:binary

上文介绍了栈缓冲区溢出的基本情况与利用方法。栈缓冲区溢出之后,如果没有任何防护措施,攻击者可以非常容易地改变程序执行逻辑,甚至可以执行注入的代码。为了降低栈缓冲区溢出漏洞发生后的风险,很多技术应运而生,ASLR(Address Space Layout Randomization,地址空间布局随机化)就是其中之一。

由于缓冲区溢出后,攻击者通常需要需要跳转到某些特定的系统函数、或是跳转到堆栈上执行,ASLR 的基本思想就是随机化动态库和堆栈空间的地址。这样就使得每次程序启动时,它们的地址都会发生变化,使得攻击者难以确定需要跳转到的目标地址。

查看系统是否开启 ASLR

Windows

Windows 自从 Vista 后全面支持了 ASLR 保护。在新版 Windows 10 中,可以在安全中心设置是否开启这一功能:

windows-aslr-settings

设置中的 “Mandatory ASLR” 是指,如果一个程序没有使用 /DYNAMICBASE 选项编译时,是否仍然要随机地址空间。由于兼容性问题存在,这项设置默认关闭。

Linux

Linux 系统中,我们可以通过 /proc/sys/kernel/randomize_va_space 来查看或开启/关闭 ASLR:

2 表示 ASLR 完全开启。设置为 0 时即为关闭。

为程序启用 ASLR

由于启用了 ASLR 后,程序的加载位置会随机变化,因此这还需要编译器的支持。GCC 可以通过使用 -pie 选项(默认开启)来生成位置无关的代码,从而使得程序能够支持 ASLR。使用 -no-pie 不会生成位置无关代码。这两种方式生成的可执行文件的信息是不同的:

在系统启用了 ASLR 时,通过 /proc/PID/maps 将可以看到,每次执行时程序所需要的动态库和堆栈空间的加载位置都不同。如果程序启用了 -pie,将会看到可执行文件自身的加载地址也会发生变化。

在 Windows 上,MSVC 的编译选项 /DYNAMICBASE 具有类似的效果。

Notes

新版 GDB 在调试时会默认关闭被调试程序的 ASLR。可以通过命令 set disable-randomization off 重新启用。

绕过 ASLR

在某些情况下,我们可以绕过 ASLR 的防护。例如,

  1. 如果缓冲区足够大,当希望跳转至缓冲区中执行指令时,可以尝试通过大量填充 NOP 使得跳转成功的机率增加。
  2. 某个寄存器中的值刚好指向了我们需要的地址。
  3. 通过某些方式泄露出动态库的加载地址。
  4. 2016 年的一篇论文指出,可以利用分支指令通过旁路探测出模块加载的地址。

内核地址空间随机化

内核同样可以开启 ASLR,这项技术在 Linux 中被称作 KASLR。但由于 2018 年 Intel CPU 所暴露出的漏洞,KASLR 不再安全。目前 KASLR 已被 KPTI(内核页表隔离)所取代。

dontpan1c 的 CTF 笔记
南阳一出即相,淮阴一出即将。

知识共享许可协议

本站所有作品均采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本站不包含明令禁止公开解题过程的题目。

本站由 Jekyll 强力驱动。