C++ 什么是缓冲区溢出,我该如何导致?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/574159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:01:50  来源:igfitidea点击:

What is a buffer overflow and how do I cause one?

c++buffer-overflowfortify-source

提问by H4cKL0rD

I have heard about a buffer overflow and I would like to know how to cause one.

我听说过缓冲区溢出,我想知道如何导致缓冲区溢出。

Can someone show me a small buffer overflow example? New(And what they are used for?)

有人可以给我看一个小的缓冲区溢出示例吗?新的(它们是用来做什么的?)

采纳答案by David Dean

A buffer overflow is basically when a crafted section (or buffer) of memory is written outside of its intended bounds. If an attacker can manage to make this happen from outside of a program it can cause security problems as it could potentially allow them to manipulate arbitrary memory locations, although many modern operating systems protect against the worst cases of this.

缓冲区溢出基本上是指将精心设计的内存部分(或缓冲区)写入其预期范围之外。如果攻击者能够设法从程序外部实现这一点,则可能会导致安全问题,因为这可能允许他们操纵任意内存位置,尽管许多现代操作系统都会防止最坏的情况发生。

While both reading and writing outside of the intended bounds are generally considered a bad idea, the term "buffer overflow" is generally reserved for writingoutside the bounds, as this can cause an attacker to easily modify the way your code runs. There is a good article on Wikipedia about buffer overflowsand the various ways they can be used for exploits.

虽然在预期范围之外读取和写入通常被认为是一个坏主意,但术语“缓冲区溢出”通常保留用于在范围外写入,因为这可能导致攻击者轻松修改您的代码运行方式。维基百科上有一篇关于缓冲区溢出及其可用于漏洞利用的各种方式的好文章。

In terms of how you could program one yourself, it would be a simple matter of:

就您如何自己编程而言,这将是一个简单的问题:

char a[4];
strcpy(a,"a string longer than 4 characters"); // write past end of buffer (buffer overflow)
printf("%s\n",a[6]); // read past end of buffer (also not a good idea)

Whether that compiles and what happens when it runs would probably depend on your operating system and compiler.

是否编译以及运行时会发生什么可能取决于您的操作系统和编译器。

回答by Johannes Schaub - litb

Classical example of a buffer-overflow:

缓冲区溢出的经典示例:

// noone will ever have the time to type more than 64 characters...
char buf[64];
gets(buf); // let user put his name

The buffer overflow alone does most often not happen purposely. It happens most often because of a so-called "off-by-one" error. Meaning you have mis-calculated the array-size by one - maybe because you forgot to account for a terminating null character, or because some other stuff.

单独的缓冲区溢出通常不是故意发生的。它最常发生是因为所谓的“一对一”错误。这意味着您错误地将数组大小计算了 1 - 可能是因为您忘记考虑终止空字符,或者因为其他一些东西。

But it can also be used for some evil stuff. Indeed, the user long knew this hole, and then inserts say 70 characters, with the last ones containing some special bytes which overwrite some stack-slot - if the user is really tricky he/she will hit the return-address slot in the stack, and overwrites it so it jumps forward into that just inserted buffer: Because what the user entered was not his name, but his shell-code that he previously compiled and dumped out. That one will then just executed. There are some problems. For example, you have to arrange not to have a "\n" in that binary code (because gets would stop reading there). For other ways that mess with dangerous string functions, the binary zero is problematic because string functions stop copying there to the buffer. People have used xorwith two times the same value to produce a zero too, without writing a zero byte explicitly.

但它也可以用于一些邪恶的东西。事实上,用户早就知道这个漏洞,然后插入说 70 个字符,最后一个包含一些特殊字节,这些字节会覆盖一些堆栈槽 - 如果用户真的很狡猾,他/她会点击堆栈中的返回地址槽,并覆盖它以便它向前跳到刚刚插入的缓冲区中:因为用户输入的不是他的名字,而是他之前编译和转储的shell代码。那一个将被执行。有一些问题。例如,您必须安排在该二进制代码中不包含“\n”(因为gets 会停止读取)。对于与危险字符串函数混淆的其他方式,二进制零是有问题的,因为字符串函数停止复制到缓冲区。人们用过xor两次相同的值也会产生零,而无需明确写入零字节。

That's the classic way of doing it. But there are some security blocks that can tell that such things happened and other stuff that make the stack non-executable. But i guess there are way better tricks than i just explained. Some assembler guy could probably now tell you long stories about that :)

这就是经典的做法。但是有一些安全块可以告诉这些事情发生了,以及其他使堆栈不可执行的东西。但我想还有比我刚刚解释的更好的技巧。一些组装人员现在可能会告诉你关于那个的长篇故事:)

How to avoid it

如何避免

Alwaysuse functions that take a maximal-length argument too, if you are not 100%sure that a buffer is really large enough. Don't play such games as "oh, the number will not exceed 5 characters" - it will fail some day. Remember that one rocket where scientists said that the number will not exceed some magnitude, because the rocket would never be that fast. But some day, it wasactually faster, and what resulted was an integer overflow and the rocket crashed (it's about a bug in Ariane 5, one of the most expensive Computer bugs in history).

如果您不能100%确定缓冲区真的足够大,请始终使用带有最大长度参数的函数。不要玩“哦,数量不会超过5个字符”之类的游戏——它总有一天会失败。请记住,科学家说火箭的数量不会超过某个数量级,因为火箭永远不会那么快。但总有一天,它实际上更快,什么是导致整数溢出和火箭坠毁(这是关于一个错误阿丽亚娜5,在历史上最昂贵的计算机的错误之一)。

For example, instead of gets use fgets. And instead of sprintfuse snprintfwhere suitable and available (or just the C++ style things like istream and stuff)

例如,代替 gets 使用fgets。而不是sprintf使用snprintf其中合适的和可用的(或仅仅是C ++风格之类的东西istream和东西)

回答by Yuda Prawira

In the modern linux OS you can't made exploiting buffer overflow without some EXTRA experiment. why ? because you will be blocked by ASLR(Address Stack Layer Randomization) and stack protectorin this modern GNU C compiler. you will not locate memory easily because memory will fall into random memory caused by ASLR. and you will blocked by stack protectorif you try to overflow the program.

在现代 linux 操作系统中,如果没有一些额外的实验,你就无法利用缓冲区溢出。为什么 ?因为您将被这个现代 GNU C 编译中的ASLR(地址堆栈层随机化)和堆栈保护器阻止。你不会轻易定位内存,因为内存会落入由ASLR引起的随机内存。如果您试图溢出程序,您将被堆栈保护器阻止。

For begining you need to put of ASLR to be 0 default value is 2

开始时,您需要将 ASLR 设为 0 默认值为 2

root@bt:~# cat /proc/sys/kernel/randomize_va_space
2
root@bt:~# echo 0 > /proc/sys/kernel/randomize_va_space
root@bt:~# cat /proc/sys/kernel/randomize_va_space
0
root@bt:~#

in this is case not about OLD STYLE buffer overflow tutorial you may got from internet. or aleph one tutorial will not work anymore in your system now.

在这种情况下,不是关于您可能从互联网上获得的 OLD STYLE 缓冲区溢出教程。或 aleph one 教程现在在您的系统中将不再适用。

now lets make a program vulnerability to buffer overflow scenario

现在让我们制作一个程序漏洞来缓冲溢出场景

---------------------bof.c--------------------------
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv)
{
        char buffer[400];
        strcpy(buffer, argv[1]);

        return 0;
}
---------------------EOF-----------------------------

looks at strcpy function is dangerous without stack protector, because function without checking how many bytes we will input. compile with extra option -fno-stack-protector dan -mpreferred-stack-boundary=2for take off stack protector in your C program

在没有堆栈保护器的情况下查看 strcpy 函数是危险的,因为函数没有检查我们将输入多少字节。使用额外选项编译-fno-stack-protector dan -mpreferred-stack-boundary=2用于在 C 程序中取消堆栈保护器

root@bt:~# gcc -g -o bof -fno-stack-protector -mpreferred-stack-boundary=2 bof.c
root@bt:~# chown root:root bof
root@bt:~# chmod 4755 bof

buffer overflow C program with SUID root access scenatio now we have make it. now lets search how many bytes we need to put into buffer to made a program segmentation fault

具有 SUID 根访问方案的缓冲区溢出 C 程序现在我们已经做到了。现在让我们搜索我们需要将多少字节放入缓冲区才能使程序分段错误

root@bt:~# ./bof `perl -e 'print "A" x 400'`
root@bt:~# ./bof `perl -e 'print "A" x 403'`
root@bt:~# ./bof `perl -e 'print "A" x 404'`
Segmentation fault
root@bt:~#

you see we need 404 bytes to made program segmentation fault (crash) now how many bytes we need to overwrite EIP? EIP is instruction will be executed after. so hacker do overwrite EIPto evil instruction what they want in the binary SUID on the program. if the program in the SUID root, the instruction will be runned in root access.

你看我们需要 404 字节来使程序分段错误(崩溃)现在我们需要多少字节来覆盖EIP?EIP 是之后将执行的指令。所以黑客确实在程序的二进制 SUID 中覆盖了他们想要的邪恶指令的EIP。如果程序在 SUID 的 root 中,则该指令将在 root 访问中运行。

root@bt:~# gdb -q bof
(gdb) list
1       #include <stdio.h>
2       #include <string.h>
3
4       int main(int argc, char** argv)
5       {
6               char buffer[400];
7               strcpy(buffer, argv[1]);
8
9               return 0;
10      }
(gdb) run `perl -e 'print "A" x 404'`
Starting program: /root/bof `perl -e 'print "A" x 404'`

Program received signal SIGSEGV, Segmentation fault.
0xb7e86606 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb) run `perl -e 'print "A" x 405'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `perl -e 'print "A" x 405'`

Program received signal SIGSEGV, Segmentation fault.
0xb7e800a9 in ?? () from /lib/tls/i686/cmov/libc.so.6
(gdb)

program GOT segmentation fault return code. let's input more bytes and take see to EIP register.

程序 GOT 分段错误返回码。让我们输入更多字节并查看 EIP 寄存器。

(gdb) run `perl -e 'print "A" x 406'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `perl -e 'print "A" x 406'`

Program received signal SIGSEGV, Segmentation fault.
0xb7004141 in ?? ()
(gdb)

(gdb) run `perl -e 'print "A" x 407'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `perl -e 'print "A" x 407'`

Program received signal SIGSEGV, Segmentation fault.
0x00414141 in ?? ()
(gdb)

little more

再多一点

(gdb) run `perl -e 'print "A" x 408'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/bof `perl -e 'print "A" x 408'`

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)

(gdb) i r
eax            0x0      0
ecx            0xbffff0b7       -1073745737
edx            0x199    409
ebx            0xb7fc9ff4       -1208180748
esp            0xbffff250       0xbffff250
ebp            0x41414141       0x41414141
esi            0x8048400        134513664
edi            0x8048310        134513424
eip            0x41414141       0x41414141 <-- overwriten !!
eflags         0x210246 [ PF ZF IF RF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb)

now you can do your next step...

现在你可以做你的下一步了......

回答by Tim Lesher

A buffer overflow is just writing past the end of a buffer:

缓冲区溢出只是写到缓冲区的末尾:

int main(int argc, const char* argv[])
{
    char buf[10];
    memset(buf, 0, 11);
    return 0;
}

回答by NTDLS

In addition to what has already been said, keep in mind that you'r program may or may not "crash" when a buffer overflow occurs. It shouldcrash, and you should hope it does - but if the buffer overflow "overflows" into another address that your application has also allocated - your application may appear to operate normally for a longer period of time.

除了已经说过的内容之外,请记住,当发生缓冲区溢出时,您的程序可能会也可能不会“崩溃”。它应该会崩溃,您应该希望它会崩溃 - 但是如果缓冲区溢出“溢出”到您的应用程序也分配的另一个地址中 - 您的应用程序可能看起来正常运行了更长的时间。

If you are using a later edition of Microsoft Visual Studio - I would suggest using the new secure counterparts in the stdlib, such as sprintf_s insted of sprintf, ect...

如果您使用更高版本的 Microsoft Visual Studio - 我建议在 stdlib 中使用新的安全对应物,例如 sprintf_s insted of sprintf 等...

回答by John Smith

If you want to check you program for buffer overflows, you could run it with tools like Valgrind. They will find some memory management bugs for you.

如果要检查程序是否存在缓冲区溢出,可以使用Valgrind 之类的工具运行它。他们会为您找到一些内存管理错误。

回答by ReinstateMonica Larry Osterman

The "classic" buffer overflow example is:

“经典”缓冲区溢出示例是:

int main(int argc, char *argv[])
{
    char buffer[10];
    strcpy(buffer, argv[1]);
}

That lets you play with the buffer overflow parameters and tweak them to your hearts content. The book "Hacking - The Art of Exploitation" (Link goes to Amazon) goes into great detail about how to play around with buffer overflows (purely as an intellectual exercise obviously).

这让您可以使用缓冲区溢出参数并将它们调整为您的心内容。“黑客攻击 - 利用的艺术”(链接到亚马逊)一书详细介绍了如何处理缓冲区溢出(显然纯粹是一种智力练习)。

回答by alex2k8

This should be enought to reproduce it:

这应该足以重现它:

void buffer_overflow() 
{
    char * foo = "foo";
    char buffer[10];

    for(int it = 0; it < 1000; it++) {
        buffer[it] = '*';
    }

    char accessViolation = foo[0];
}

回答by jww

This is a general comment about the answers you received. For example:

这是对您收到的答案的一般性评论。例如:

int main(int argc, char *argv[])
{
    char buffer[10];
    strcpy(buffer, argv[1]);
}
int main(int argc, char *argv[])
{
    char buffer[10];
    strcpy(buffer, argv[1]);
}

And:

和:

int main(int argc, const char* argv[])
{
    char buf[10];
    memset(buf, 0, 11);
    return 0;
}
int main(int argc, const char* argv[])
{
    char buf[10];
    memset(buf, 0, 11);
    return 0;
}

On modern Linux platforms, this may not work as expected or intended. It may not work because of the FORTIFY_SOURCE security feature.

在现代 Linux 平台上,这可能无法按预期或预期工作。由于 FORTIFY_SOURCE 安全功能,它可能不起作用。

FORTIFY_SOURCE uses "safer" variants of high risk functions like memcpyand strcpy. The compiler uses the safer variants when it can deduce the destination buffer size. If the copy would exceed the destination buffer size, then the program calls abort().

FORTIFY_SOURCE使用“更安全”的喜欢高风险的功能变体memcpystrcpy。当编译器可以推导出目标缓冲区大小时,它会使用更安全的变体。如果副本将超过目标缓冲区大小,则程序调用abort().

To disable FORTIFY_SOURCE for your testing, you should compile the program with -U_FORTIFY_SOURCEor -D_FORTIFY_SOURCE=0.

要为您的测试禁用 FORTIFY_SOURCE,您应该使用-U_FORTIFY_SOURCE或编译程序-D_FORTIFY_SOURCE=0

回答by Jcbn

Buffer overflow is the insertion of characters beyond what the allocated memory can hold.

缓冲区溢出是指插入的字符超出了分配的内存所能容纳的范围。