10

我想了解这两种攻击之间的确切区别。从我读到的:

缓冲区溢出:它覆盖堆栈上的 ret 地址以指向插入恶意代码的代码的另一部分。如此有效——这里我们需要修改程序的源代码才能真正进行攻击。

返回到 Libc——这里不是修改源代码,而是使用 C 库提供的运行时函数调用(比如打开一个 shell)。这里用于函数调用的参数也在覆盖缓冲区中传递,在堆栈的 ret 部分之后结束。

以上描述准确吗?

还有另一个相关的问题 - 是否有可能在不实际修改原始程序的源代码的情况下进行缓冲区溢出攻击?可能是如果我们编写一个新程序并允许它修改内存的某些部分(这是原始程序损坏堆栈中的新 ret 地址)。再说一次,我认为这可能是不可能的,因为内核中的进程之间提供了内存保护。

4

4 回答 4

12

在经典的缓冲区溢出漏洞利用中,被溢出的堆栈缓冲区填充了要执行的机器代码(称为 shellcode,因为它通常调用 shell 进程)和新的返回地址。新的返回地址将被设计为指向溢出的堆栈缓冲区本身。显然,这需要知道或猜测被攻击进程中该堆栈缓冲区的地址。

在那些日子里,进程的内存布局通常是高度确定的——攻击者通常可以很好地预测堆栈缓冲区的位置(特别是如果他们确切知道目标软件的哪个版本正在被攻击)。当涉及一些猜测时,为了提高成功的机会,活动的 shellcode 通常会在执行无用操作的大量可执行机器代码之前 - 称为“NOP sled”或“NOP slide”,其中“NOP”是执行“无操作”的机器代码指令的典型名称。返回到 NOP 雪橇中的任何位置都会产生预期的效果。

另一方面,“return-to-libc”利用不会导致被劫持的进程直接返回到 shellcode。相反,它会导致进程一个接一个地返回到库函数链的开头。这些库函数可能直接执行攻击者想要的操作,但更常见的是它们将用于间接执行攻击者的 shellcode。

于 2011-09-05T05:07:05.230 回答
4

覆盖 ret 地址的部分在两种攻击之间共享。正如上面的回复所示,您过去只是简单地返回您编写的汇编代码。然后,该汇编代码将生成一个 root 用户 shell。

在这两种攻击中,您都不会“覆盖”源代码。从汇编的角度来看,源代码位于 .text 段中,并且一直(或至少在我所知道的所有时间)都是写保护的。您过去利用的是编写您之前组装到内存段中的代码,然后跳转到该代码。该代码通常位于“堆栈段”中或附近,并且通过溢出您选择超限的任何内容,您将重定向来自 ret 地址(例如)那里的流量。其他攻击场所包括您之前创建并填充了您的 shellcode 的环境变量;或者堆,或函数指针,或PLT。如此插入的代码通常会使用 system() 调用来执行所需的 - 但为此,您需要能够“执行”

两种攻击之间的区别在于,一旦内存在很大程度上变得不可执行,攻击类型 a(堆栈溢出)就几乎被搞砸了。然后,在您编写时,试图绕过这种类型的攻击,而是直接访问共享库函数——也就是说,您不再需要先将代码写入堆栈段或其他地方并在那里执行它。但是,我相信 libc 类型的攻击现在也基本上得到了修补。我手头没有详细信息;也许我错了。

如果您想了解这些攻击是如何被挫败的,或者至少了解一些关键思想,请在 google 'Smashing the Stack in 2011'(或 2010)开始。

于 2011-09-05T01:30:08.453 回答
4

我想说缓冲区溢出是一类编程错误,返回 libc是一种利用技术。最好不要将这些概念混在一起。

例如,您可以使用return to libc来利用缓冲区溢出漏洞。或者您可以使用其他技术,例如返回 .text返回 shellcode。相反,您也可以使用return to libc来利用其他错误,例如格式字符串

于 2011-09-05T05:16:14.913 回答
0

实际上,在缓冲区溢出攻击中,您在覆盖 ret 指针的同时插入恶意代码。您不需要为此进行任何修改,因此作为结论,我看不出提到的两种攻击之间的区别。

例如:

char* str[5];
cin << str;

这是可以分解的代码,如果用户插入一个大于 5 个字符的字符串,则堆栈上的所有内容都将被覆盖。而且由于 ret-ptr 在堆栈上“较低”,如果距离正确,您可以覆盖它。您在覆盖时的意图是让它指向您输入的开头,您在其中插入恶意(汇编程序)代码,一旦调用 ret-ptr 并执行“跳转”,就会执行该代码。

于 2011-09-05T00:12:16.367 回答