【51CTO.com快译】地址空间布局随机化(ASLR)是操作系统的一种保护内存的进程,旨在防范缓冲区溢出攻击。它有助于确保与系统上运行中的进程关联的内存地址不可预测,因此让攻击者更难利用与这些进程有关的缺陷或漏洞。
ASLR目前用于Linux、Windows和MacOS三大系统。2005年它首次实现在Linux上。2007年,这项技术部署在微软Windows和MacOS上。虽然ASLR在这每一款操作系统上提供了一样的功能,但它实现在每个操作系统上的方式都不一样。
ASLR的效果取决于攻击者仍然未知的全部地址空间布局。此外,只有编译成位置独立的可执行程序(PIE)的可执行文件才能从ASLR技术得到最大程度的保护,因为代码的所有部分都将在随机位置装入。无论绝对地址如何,PIE机器码都会正确执行。
ASLR的局限性
尽管ASLR让人更难利用系统漏洞,但其在保护系统方面的作用有限。了解ASLR的局限性很重要:
- 不解决漏洞,而是加大利用漏洞的难度
- 不跟踪或报告漏洞
- 不为不支持ASLR而开发的二进制代码提供任何保护
- 无法避免规避机制
ASLR的工作原理
ASLR加大了系统的控制流完整性,为此使内存布局中使用的偏移随机化,从而让攻击者更难执行成功的缓冲区溢出攻击。
ASLR在64位系统上的效果要好得多,因为这类系统提供了大得多的熵(随机化潜力)。
ASLR是否可以用在你的Linux系统上?
下列两个命令中的任何一个都可以告诉你ASLR在你的系统上是否已启用。
- $ cat /proc/sys/kernel/randomize_va_space
- 2
- $ sysctl -a --pattern randomize
- kernel.randomize_va_space = 2
上述命令中所示的值(2)表明,ASLR在完全随机化模式下工作。显示的值将是下列中的一个:
- 0 = 被禁用
- 1 = 保守随机化
- 2 = 完全随机化
如果你禁用ASLR并运行下列命令,会注意到下面ldd输出中显示的地址在随后的ldd命令中都一样。ldd命令的工作原理是,装入共享的对象,并显示它们最后出现在内存中的哪个位置。
- $ sudo sysctl -w kernel.randomize_va_space=0 <== disable
- [sudo] password for shs:
- kernel.randomize_va_space = 0
- $ ldd /bin/bash
- linux-vdso.so.1 (0x00007ffff7fd1000) <== same addresses
- libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007ffff7c69000)
- libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ffff7c63000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7a79000)
- /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fd3000)
- $ ldd /bin/bash
- linux-vdso.so.1 (0x00007ffff7fd1000) <== same addresses
- libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007ffff7c69000)
- libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ffff7c63000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7a79000)
- /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fd3000)
如果该值设回成2以启用ASLR,你会发现每当你运行该命令,地址都会变化。
- $ sudo sysctl -w kernel.randomize_va_space=2 <== enable
- [sudo] password for shs:
- kernel.randomize_va_space = 2
- $ ldd /bin/bash
- linux-vdso.so.1 (0x00007fff47d0e000) <== first set of addresses
- libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f1cb7ce0000)
- libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1cb7cda000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1cb7af0000)
- /lib64/ld-linux-x86-64.so.2 (0x00007f1cb8045000)
- $ ldd /bin/bash
- linux-vdso.so.1 (0x00007ffe1cbd7000) <== second set of addresses
- libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007fed59742000)
- libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fed5973c000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fed59552000)
- /lib64/ld-linux-x86-64.so.2 (0x00007fed59aa7000)
试图绕过ASLR
尽管ASLR有诸多优点,但试图绕过ASLR并不罕见,似乎属于这几类:
- 使用地址泄露
- 访问与特定地址有关的数据
- 利用实现方面的薄弱环节,熵很低或ASLR实现存在缺陷时,让攻击者得以猜出地址。
- 使用硬件操作的侧通道
结束语
ASLR大有价值,尤其是在64位系统上运行、正确实现时。虽然无法避免规避机制,但它确实大大增加了利用系统漏洞的难度。这份参考资料(https://cybersecurity.upv.es/attacks/offset2lib/offset2lib-paper.pdf)更详细地介绍了64位Linux上是完全ASLR的效果,而这篇论文(http://www.cs.ucr.edu/~nael/pubs/micro16.pdf)介绍了使用分支预测绕过ASLR的一种规避方法。
原文标题:How ASLR protects Linux systems from buffer overflow attacks,作者:Sandra Henry-Stocker
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】