- 缓冲区溢出和返回libc攻击之间的区别

时间:2011-09-05 00:01:39

标签: c security buffer-overflow shellcode

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

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

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

以上是准确的描述吗?

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

4 个答案:

答案 0 :(得分:12)

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

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

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

答案 1 :(得分:4)

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

在这两种攻击中,你都会“覆盖”源代码。从汇编的角度来看,源代码位于.text段中,并且一直(或者至少我知道的所有时间)都是写保护的。您曾经利用的是编写先前已组装到内存段中的代码,然后跳转到此代码。代码通常位于“堆栈段”中或附近,并且通过溢出任何您选择的溢出,您将重新引导来自转发地址(例如)的流量。其他攻击场所包括您之前创建并填充shellcode的环境变量;或者堆,或函数指针,或PLT。这样插入的代码通常会使用system()调用来执行所需的操作 - 但是为此,您需要能够在内存区域上“执行”(或者您打算使用的重定位条目被声明为可写)。 / p>

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

如果您想了解这些攻击中的任何一种如何被挫败,或者至少阅读一些关键想法,请谷歌“在2011年粉碎堆栈”(或2010年)开始。

答案 2 :(得分:4)

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

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

答案 3 :(得分:0)

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

例如:

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

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