简体   繁体   English

尝试缓冲区溢出

[英]Experimenting with buffer overflow

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. 我试图跟进,但是在Debian虚拟机而不是Windows中。

This is the C code from the site: 这是网站的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;
}

The code "cheats" by giving the addresses of the two functions foo and bar. 代码通过给出两个函数foo和bar的地址来“欺骗”。 The ultimate goal is to get bar to run using only buffer overflow. 最终目标是使用缓冲区溢出来运行bar。 To do this, they gave a short Perl script: 为此,他们给出了一个简短的Perl脚本:

$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: 由于我使用的是Linux而不是Windows,并且因为我的bar函数的地址略有不同,所以我做了几个简单的修复:

$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 . 运行Perl脚本,它将填充文本提供给程序,然后是运行bar的新返回地址。 But it doesn't work for me. 但它对我不起作用。

This is the output from running my Perl script: 这是运行我的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

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. 我怀疑这个问题来自使用gcc来编译我的程序,但我不确定究竟是什么导致它。 The issue may also be Debian. 这个问题也可能是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. 实际上我可以简单地切换到Windows,但此时我真的想知道为什么它不起作用以及如何解决它。

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. 如果您按照问题中的链接进行操作,您会看到打印堆栈的6个内存地址对于他们的系统来说已经足够了,但这对我们来说还不够。 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. 首先,它增加了打印到13的地址量。其次,它打印缓冲区开始的地址。 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 . 在这个例子中,我们可以看到Address of Buffer: 0x7ffddab71220 If we look through the stack addresses below it, we find one very similar: 0x7ffddab72653 . 如果我们查看它下面的堆栈地址,我们会发现一个非常相似的: 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. 事实上,在这个例子中,我将“ZZZZZZ”打印到缓冲区,你可以看到紧跟我们起点的地址已经变为0x5a5a5a5a5a5a ,你可能已经猜到了,这是十六进制的“ZZZZZZ”。

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 . Address of foo = 0x400596 Address of bar = 0x400601我们可以在缓冲区起始点之下找到一个类似的值,在这种情况下: 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. 此时,需要尝试使用perl脚本,在缓冲区中添加字符,直到得到所需的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM