有什么需要随机化内存地址来加载库?

时间:2010-10-20 19:20:58

标签: c memory random shared-libraries

ldd显示共享库在运行时链接的内存地址

$ cat one.c 
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc one.c -o one -O3
$ ldd one
    linux-gate.so.1 =>  (0x00331000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00bc2000)
    /lib/ld-linux.so.2 (0x006dc000)
$

this answer到另一个问题,

  

......地址基本上是随机数。在设计安全实现之前,ldd将始终指示加载程序段的内存地址。从大约五年前开始,许多版本的Linux现在故意随意加载地址以挫败潜在的病毒编写者等。

我不完全理解这些内存地址如何用于开发。

问题是“如果地址是固定的,那么可以在该地址放置一些不需要的代码,这些代码就像是一个库一样被链接”或者它不仅仅是这个?

4 个答案:

答案 0 :(得分:3)

  

“如果地址是固定的,可以在该地址放置一些不需要的代码,这些代码将被链接,就好像它是一个库”

另外。缓冲区溢出漏洞需要一致的内存模型,以便溢出缓冲区的字节对代码的已知部分做了已知的事情。

http://www.corewars.org/这个原则的一个很好的例子。

答案 1 :(得分:3)

某些漏洞允许覆盖某些地址(堆栈溢出允许覆盖返回地址,利用堆溢出通常会覆盖Win32上的SEH指针和Linux上动态调用函数的地址(GOT条目),...)。因此攻击者需要将覆盖的地址指向有趣的东西。为了使这一点变得更加困难,已采取了几项措施:

  • 不可执行的堆栈可以防止攻击只是跳转到攻击者放入堆栈的某些代码。
  • W ^ X段(永远不可写并且可以同时执行的段)阻止其他内存区域相同。
  • 库的随机加载地址和位置无关的可执行文件通过return-into-libc和面向返回的编程技术降低了成功利用的可能性,......
  • 随机加载地址还可以防止攻击者事先知道在哪里找到一些有趣的功能(例如:想象一个可以覆盖GOT条目的攻击者和下一次日志记录调用的部分消息,知道{{1}的地址将是“有趣的”)。

因此,您必须将加载地址随机化视为许多(几个防御层以及所有这些)中的另一个对策。

另请注意,漏洞利用不限于任意代码执行。获取程序来打印一些敏感信息而不是(或者除了,想到字符串截断错误)一些非敏感信息也被视为漏洞利用;用这种漏洞编写一些概念验证程序并不困难,因为知道绝对地址会使可靠的漏洞成为可能。

你一定要看一下return-into-libc和面向返回的编程。这些技术大量使用可执行文件和库中的地址知识。

最后,我会注意到有两种方法可以随机化库加载地址:

  • 在每次加载时执行此操作:即使攻击者可以在一次运行中获取有关地址的信息并尝试在另一次运行中使用该信息,这会使(某些)攻击不太可靠。
  • 每个系统执行一次:这是prelink -R的功能。它避免了攻击者使用通用信息,例如:所有Redhat 7.2框。显然,它的优点是它不会干扰预链接:)。

答案 2 :(得分:2)

一个简单的例子:

如果在流行的操作系统上,标准C库总是在地址0x00100000处加载,并且标准C库的最新版本在偏移量0x00000100处具有system函数,那么如果有人能够利用其中的缺陷在具有此操作系统的计算机上运行的程序(例如Web服务器)导致它将一些数据写入堆栈(通过缓冲区溢出),他们会知道如果他们将0x00100100写入堆栈中的位置很可能当前函数期望其返回地址为,那么它们可以使得当从当前函数返回时将调用system函数。虽然他们仍然没有完成使system执行他们想要的东西所需的一切,但他们很接近,并且有一些技巧会将更多东西写入堆栈,而上述地址的可能性很高导致有效字符串指针和强制调用system运行的命令(或一系列命令)。

通过随机化加载库的地址,攻击者更有可能使Web服务器崩溃,而不是获得对系统的控制权。

答案 3 :(得分:1)

典型的方法是通过缓冲区溢出,将特定地址放在堆栈上,然后返回到它。您通常会在内核中选择一个地址,它假设已经在堆栈上传递的参数已被检查,因此它只是使用它们而无需进一步检查,从而允许您执行通常不允许的操作。 / p>