【问题标题】:Difference between - buffer overflow and return to libc attack缓冲区溢出和返回libc攻击的区别
【发布时间】:2011-09-05 00:01:39
【问题描述】:

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

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

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

以上描述准确吗?

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

【问题讨论】:

    标签: c security buffer-overflow shellcode


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      如果您想了解这些攻击是如何被阻止的,或者至少了解一些关键想法,请在 Google 上搜索“Smashing the Stack in 2011”(或 2010)开始。

      【讨论】:

      • 你能解释一下你的意思 - 使内存可执行(或不可执行)。另一个疑问(我最初的问题的一部分)是 - 我相信 C 代码无法访问主存储器的所有部分。那么如何确定恶意汇编代码在内存中的位置。因为我认为对于大多数内存区域 - 它只会在返回时标记分段错误。
      • 您插入的漏洞利用代码的核心通常是使用和 exec() 系列风格的函数。这意味着,通过为其提供适当的参数,您可以让它以 root 用户身份生成 /bin/sh shell。这是执行一个程序,你不能再这样做了。有许多不同的安全措施,但会描述一个,例如,在
      • 对于破碎的评论感到抱歉 - 我的浏览器出了点问题。例如,如果您运行 Ubuntu,这里显示了当前实现的内容:wiki.ubuntu.com/Security/Features
      • 你写你'怀疑c代码可以访问内存的所有部分'。这也是正确的,但这只是您面临的整套措施的一部分。一个例子是(我在 Ubuntu 下工作,但在其他地方会类似)金丝雀值的设置(你也可以用谷歌搜索)。
      • 如果您使用 gcc,请使用 -fno-stack-protector 编译一次,一次 w/o,然后查看反汇编。您会注意到 ebp 附近对 gs:14 的引用,它设置了金丝雀值,并且您无法读取,也无法写入 - 至少没有我知道的任何技巧。分段错误的标记,你是对的,是对检测到攻击尝试的一般响应。但是,这并不意味着您必须尝试覆盖返回地址,尽管通常会这样做。
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        例如:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-23
          • 2011-11-12
          • 1970-01-01
          • 1970-01-01
          • 2021-12-03
          • 2021-02-25
          • 1970-01-01
          • 2019-04-14
          相关资源
          最近更新 更多