[英]Hacking - The Art of Exploitation: debugging buffer overflow example
[英]Stack-based overflow code from Hacking: The Art of Exploitation
这可能与此有关,但我不确定是否在同一条船上。
因此,我一直在重新阅读《黑客:剥削的艺术》,我对书中的某些C代码有疑问,这对我来说意义不大:
让我们假设我们回到了2000年左右,而我们实际上并没有堆栈cookie和ASLR(也许可以,但是尚未实现或未广泛使用),或者我们现在没有任何其他类型的保护-一个天。
他向我们展示了这段代码,以利用基于堆栈的简单溢出:
#include <stdlib.h>
char shellcode[] = "..." // omitted
unsigned long sp(void)
{ __asm__("movl %esp, %eax); }
int main(int argc, char *argv[]) {
int i, offset;
long esp, ret, *addr_ptr;
char *buffer, *ptr;
offset = 0;
esp = sp();
ret = esp - offset;
// bunch of printfs here...
buffer = malloc(600);
ptr = buffer;
addr_ptr = (long *) ptr;
for(i = 0; i < 600; i+=4)
{ *(addr_ptr++) = ret; }
for(i = 0; i < 200; i++)
{ buffer[i] = '\x90'; }
ptr = buffer + 200;
for(i = 0; i < strlen(shellcode); i++)
{ *(ptr++) = shellcode[i]; }
buffer[600-1] = 0;
execl("./vuln", "vuln", buffer, 0);
free(buffer);
return 0;
}
因此,他想要做的就是获取ESP的地址,并用该地址覆盖保存的EIP,以便处理器将跳转到内存中的NOP底座并在堆栈中执行Shellcode。
我不了解的是,他如何使用当前调用时从sp()获得的特定ESP值。
据我了解,堆栈看起来像“东西”:
...
saved ebp <-- execl
saved eip
"./vuln"
"vuln"
buffer
0
*ptr <-- sp() returns this address?
*buffer
*addr_ptr
ret
esp
offset
i
saved ebp <-- main
saved eip
argc
argv
...
由于他在漏洞利用的早期就调用了(我知道这是一个函数指针,所以我猜不是完全准确的措辞吗?)sp(),它不应该给他一个错误的ESP地址吗? 即使如此,我也看不出他怎么能在这里使用该技术,因为他将永远不会获得指向vuln程序内部缓冲区顶部的ESP。
谢谢。
我什至看不到他怎么可以在这里使用该技术,因为他永远不会获得指向vuln程序内部缓冲区顶部的ESP。
我没有读太多书,但是我想我已经明白了。 这是*buffer
样子:
NOP sled | shellcode | Address of buffer in the exploit's stack frame
当vuln
做strcpy()
上buffer
到它自己的堆栈,它无法检查的范围和覆盖自己的EIP与缓冲区的起始地址信息中的漏洞的堆栈帧,或者至少接近它(因此NOP雪橇)。 NOP vuln
和复制到vuln
堆栈框架的shellcode是偶然的; 那不是他们的出发地。 至关重要的是, vuln
和shellcode必须小于 vuln
期望的buffer
,否则保存的EIP将被shellcode而不是buffer
的地址覆盖。
然后,当在buffer
上使用strcpy()
的vuln
任何部分返回时,它将转到NOP底座并执行shellcode。
重要的一点是buffer
在两个不同的位置读取了两次 。
编辑:忽略这一点,我感到困惑(尽管感谢您的接受!)。 希望我也不会混淆您,这就是为什么我要编写此编辑内容。 易受攻击的程序位于完全不同的虚拟内存空间中,因为它是由操作系统在单独的进程中运行的(或具有新映像的同一进程?无论如何)。 因此, vuln无法访问漏洞利用程序的堆栈或堆。
ESP技巧必须是某种猜测猜测复制缓冲区中的NOP滑板在vuln堆栈中最终位置的方式。 我个人希望偏移量比0大得多,因为漏洞利用的堆栈比vuln的堆栈小。
就是说,我很确定vuln中仍然有两个Shellcode 副本 (否则,它的strcpy()
可能来自什么?)。 偏移量为0,也许他正在运行存储在argv [] ...?!中的shellcode。 在那种情况下,您仍然会遇到这样的情况,一个缓冲区中的地址指向另一个缓冲区中的NOP底座,就像我的原始答案一样。 我以前错了,所以让我知道是否没有道理。
在很大程度上取决于代码打算使用的特定操作系统。 在不知道这一点的情况下,任何讨论都必须有点泛泛[我的猜测也是这样]。
一种可能性是您遗漏的“ printfs束”中有一些重要内容...
如果真的没有什么聪明的事情发生,我想它试图利用的漏洞在有效传递长(600字节)命令行参数时在execl(..)
调用和/或OS中。 在某个地方(我猜是),一个子例程将为新进程设置环境,并且在此过程中,将作为参数( buffer
)传入的600字节字符串复制到一个很小的( ish)在新进程的堆栈上固定大小的缓冲区,并且[大概]用原始调用中的堆栈指针的许多副本覆盖此“设置”函数的返回地址。 当“命令行复制功能”返回时,它将因此从原始副本返回到精心准备的buffer
并执行shellcode。
(如果省略的shellcode
包含一个零字节...\\x00...
那么就不可能发生这种情况,因为它会在设置命令行缓冲区时标记要复制的字符串的结尾)。
:)我已经在这里待了好几天试图找出实际情况。 在此过程中,我还发现了这篇文章。 现在,我对发生的事情有了一个大致的了解,我认为我应该分享自己的理解,这样像“我”这样的其他人也会发现这很有用。
unsigned long getesp()
{
__asm__("movl %esp, %eax");
}
该函数实际上用于猜测返回地址。 它返回我们的shellcode注入程序的ESP值,而不是易受攻击程序的ESP值。 但是由于堆栈从几乎相同的地址开始(对于未启用ASLR的系统),并且正如aleph在其文章中提到的那样:“大多数程序在任何时候都不会将数百或几千个字节推入堆栈。因此,通过知道堆栈从哪里开始,我们可以尝试猜测我们试图溢出的缓冲区将在哪里,我们可以了解shellcode应该在哪里。 让我解释。
假设对于我们的测试程序,堆栈从1000开始。执行该地址时,上述代码实际上返回了该地址。 现在考虑我们易受攻击的程序,并假设我们要注入的缓冲区位于地址970,返回地址存储在1040。
[BUFFER 970] [RETURN_ADDRESS 1070]
好? 现在,缓冲区以NOPS归档,直到前半部分,然后是shellcode,然后是正确的返回地址。
[NOP SLED] [SHELL_CODE] [RETURN_ADDRESS]
让我们这样填充
NOPS [970-1010] SHELLCODE [1010-1050] RETURN_ADDRESS [1050-1070]
getesp()返回的值使您可以了解堆栈的位置。 因此,如果我们将getesp()返回的返回地址重写为1000,则可以看到该漏洞利用仍然有效,因为1000处的地址是通过nops提交的。 执行将滑落到shellcode!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.