当我覆盖一个易受攻击程序的ret地址时,为什么会出现"Cannot find bound of current function"?

10

我希望为教育目的利用基于堆栈的缓冲区溢出。

有一个典型的函数从主函数中调用,该函数使用从程序输入的参数作为本地缓冲区,并将参数保存在其中。如果给定一个这样的输入:nops+shellcode+address_shellcode,我将利用它。

通过gdb调试,我找到了shell code的地址,因为它将作为参数传递,并且在strcpy之后,我检查了堆栈和$ebp+8(即返回地址),成功地覆盖了shell code的地址。所以我得到了想要的东西。但是当我向前执行时,我得到了:

->shellcode_address in ?? ()

然后

Cannot find bound of current function

返回地址具有我想要的值。有什么想法这是怎么发生的吗?

此外,当我执行它时,我得到了一个分段错误,并且我已经使用-g -fno-stack-protector编译它。为什么?


请查看https://dev59.com/hnE95IYBdhLWcg3wMa51,它解释了"Cannot find bounds of current function"的意思只是gdb没有当前指令指针的调试信息,并且对此状态不满意。但您可能还有其他问题。 - Steve Jessop
我该如何为nop指令添加调试信息,该指令后跟其他nop指令,并以shellcode结尾? - curious
我不确定gdb的确切工作方式,但我猜你也不知道。 gdb在其大型旧调试信息表中查找指令指针的地址,该表是从它所知道的可执行文件加载的。但是指令指针位于堆栈上,没有任何调试信息覆盖它。也许理论上你可以综合一些关于当前堆栈地址的DWARF数据,并将其加载到gdb中,但我不知道该怎么做。 - Steve Jessop
我不这么认为。这只是一个简单的基于堆栈的缓冲区溢出攻击。我还缺少其他东西。 - curious
5个回答

9

调试器了解程序中函数代码的起始和终止位置,这要么是通过调试数据提供的信息,要么是使用可执行文件中可见的任何外部符号来提供基本信息。

当堆栈处于适当状态时,它包含调用函数的返回地址,以及某个位置上方的更高级别调用函数的返回地址,以此类推。在执行各种调试器命令时,它使用这些返回地址(以及堆栈和进程状态中的其他信息)来显示函数的名称。这需要在调试器对函数位置的知识中查找返回地址。

一旦你溢出缓冲区并破坏了堆栈,则正确的返回地址就被破坏了。相反,你有一个不同的地址(如果你的攻击成功,则指向你的 shellcode)。当调试器尝试确定此地址在哪个函数中时,它会失败,因为地址不在程序的任何函数中。

当发生这种失败时,调试器会打印出你看到的错误消息。

通常,调试器仍然可以执行基本的功能:它可以显示程序中的寄存器和内存,它仍然可以单步执行和设置断点等。它将无法执行需要更复杂的解释的操作:它无法找到堆栈框架的位置,无法按名称查找局部变量等。


3

很有可能在函数中存在缓冲区溢出问题(或类似问题)。它会用无关的数据覆盖您函数的当前堆栈帧,并在此过程中破坏返回地址,该地址通常存储在其中。结果是代码“返回”到某个不可预测的位置,并且无法确定返回到哪里。这就是导致错误消息的原因。


1
你通过函数返回地址损坏了寄存器。返回地址现在非法,调试器无法访问它。因此出现了该错误信息。

1

你正在堆栈上执行代码,并询问 GDB 你在哪个函数中。
显然,GDB 感到困惑,因为你不在任何函数中。所以它显示地址和“??”

你必须使用 -no-stack-protector 编译,因为堆栈保护程序正是保护你正在尝试做的事情。
我并不是说没有绕过它的方法,但这需要更多的努力和对其保护机制的深入理解。


为什么我不在任何函数中?我在我的函数内部,该函数已被主函数调用。我将myfunction的返回地址更改为堆栈上nops和shellcode所在的地址。我使用-fno-stack-protector编译。我已经提到过了。 - curious
一旦您将返回地址更改为shellcode,并跳转到返回操作,您就进入了shellcode,而不是任何函数。我以为您在问为什么需要使用无堆栈保护编译,并回答了。 - ugoren
据我所知,除了使用覆盖返回地址为壳代码地址的nops指令之外,我不知道还有其他方法来生成shell。我错了吗? - curious
有许多方法可以实现。您可以变换shellcode的位置 - 堆栈、堆甚至使用现有的libc代码(“跳转到libc”)。您还可以使用不同的方法跳到它 - 覆盖函数指针,VFT(在C++中),malloc控制结构。而您要跳转的代码也可以有很多变化。一个严肃的黑客可能会添加更多内容。 - ugoren
我想将它作为输入参数传递给程序,该程序将是易受攻击函数的参数。 - curious
谁投了反对票?为什么?这是目前唯一一个回答了调试器显示的信息“无法找到当前函数的边界”的答案。这个答案符合观察到的行为:缓冲区溢出破坏了调试器用来解释堆栈并确定正在执行哪个函数的数据。这种破坏导致调试器无法完成其工作并显示错误消息。 - Eric Postpischil

0

假设您的Linux发行版是最新的,并且您正在使用x86ish架构,那么您将无法再从用户空间内存执行shell代码(这也适用于其他架构,只是我不太熟悉它们)。有许多原因,对于您的情况,最有可能的是nx位的设置。转到您的Linux安全手册页面,您将看到大量默认启用的安全措施;并且可以通过谷歌搜索“2011年趣味性地破坏堆栈”来寻找可能的解决方法。使用“-fno-stack-protector”编译仅意味着不设置金丝雀值;但这还不够。如果您想出于教育目的而这样做,我建议安装像virtualbox这样的虚拟机,并在其中安装旧的发行版。


这可能解释了为什么尝试执行不正确的代码会导致访问冲突。它如何解释调试器显示的“无法找到当前函数的绑定”消息? - Eric Postpischil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接