什么是缓冲区溢出以及如何导致缓冲区溢出?

发布于 2024-07-13 22:44:22 字数 78 浏览 15 评论 0原文

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

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

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?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

橪书 2024-07-20 22:44:22

缓冲区溢出的经典示例:

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

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

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

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

如何避免它

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

例如,使用 fgets 代替 gets。 在合适且可用的地方使用 snprintf 而不是 sprintf (或者只是 C++ 风格的东西,比如 istream 之类的东西)

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.

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 xor with two times the same value to produce a zero too, without writing a zero byte explicitly.

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

Always use 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 was actually 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).

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

隱形的亼 2024-07-20 22:44:22

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

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

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

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)

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

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 writing outside 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 overflows and 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.

不一样的天空 2024-07-20 22:44:22

在现代 Linux 操作系统中,如果不进行一些额外的实验,就无法利用缓冲区溢出。
为什么 ? 因为在这个现代 GNU C 编译器中,您将被 ASLR(地址堆栈层随机化)和堆栈保护器阻止。 您将无法轻松定位内存,因为ASLR会导致内存陷入随机内存。 如果您尝试溢出程序,您将被堆栈保护器阻止。

首先你需要将 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:~#

这种情况与您可能从互联网上获得的 OLD STYLE 缓冲区溢出教程无关。 或者 aleph one 教程现在将不再在您的系统中运行。

现在让我们制作一个缓冲区溢出漏洞的程序,

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

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

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

看看 strcpy 函数在没有堆栈保护器的情况下是危险的,因为函数不检查我们将输入多少字节。
使用额外选项 -fno-stack-protector dan -mpreferred-stack-boundary=2 进行编译,以便在具有 SUID 根访问场景的 C 程序缓冲区溢出 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

现在我们已经成功了。
现在让我们搜索一下我们需要放入缓冲区多少字节才能产生程序分段错误,

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:~#

您会看到我们需要 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)

程序 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)

......

(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)

现在你可以做下一步了

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 protector in 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 protector if you try to overflow the program.

For begining you need to put of ASLR to be 0
default value is 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.

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=2 for take off stack protector in your C program

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

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 EIP to 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.

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.

(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...

柠檬心 2024-07-20 22:44:22

缓冲区溢出只是写入超过缓冲区末尾:

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

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;
}
北城半夏 2024-07-20 22:44:22

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

如果您使用的是 Microsoft Visual Studio 的更高版本 - 我建议使用 stdlib 中新的安全对应项,例如 sprintf_s 替换 sprintf 等...

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 should crash, 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...

如梦亦如幻 2024-07-20 22:44:22

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

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

它允许您使用缓冲区溢出参数并将它们调整到您想要的内容。 “黑客 - 剥削的艺术”一书(链接转到亚马逊)详细介绍了如何解决缓冲区溢出问题(显然纯粹是一项智力练习)。

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).

↘紸啶 2024-07-20 22:44:22

这应该足以重现它:

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

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

    char accessViolation = foo[0];
}

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];
}
烟若柳尘 2024-07-20 22:44:22

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

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.

嘿看小鸭子会跑 2024-07-20 22:44:22

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

int main(int argc, char *argv[]) 
  { 
      字符缓冲区[10]; 
      strcpy(缓冲区, argv[1]); 
  } 
  

和:

int main(int argc, const char* argv[]) 
  { 
      字符缓冲区[10]; 
      memset(buf, 0, 11); 
      返回0; 
  } 
  

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

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

要在测试中禁用 FORTIFY_SOURCE,您应该使用 -U_FORTIFY_SOURCE-D_FORTIFY_SOURCE=0 编译程序。

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]);
}

And:

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.

FORTIFY_SOURCE uses "safer" variants of high risk functions like memcpy and 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().

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

雨落□心尘 2024-07-20 22:44:22

在这种情况下,缓冲区是为特定目的而留出的内存的一部分,缓冲区溢出是指当对缓冲区的写入操作持续超过末尾(写入具有不同目的的内存)时发生的情况。 这始终是一个错误。

缓冲区溢出攻击是一种利用此错误来完成程序作者不希望完成的事情的攻击。

In this context, a buffer is a portion of memory set aside for a particular purpose, and a buffer overflow is what happens when a write operation into the buffer keeps going past the end (writing into memory which has a different purpose). This is always a bug.

A buffer overflow attack is one which uses this bug to accomplish something that the program's author didn't intend to be possible.

我的鱼塘能养鲲 2024-07-20 22:44:22

给出正确答案后:要详细了解此主题,您可能需要收听 Podcast Security Now。 在第39集(不久前)中,他们深入讨论了这一点。 这是一种无需消化整本书即可获得更深入理解的快速方法。

(如果您比较注重视觉效果,您可以在链接中找到具有多种尺寸版本的存档以及转录本)。 音频并不是这个主题的完美媒介,但史蒂夫正在努力解决这个问题。

With the correct answers given: To get more into this topic, you might want to listen to the Podcast Security Now. In Episode 39 (a while back) they discussed this in depth. This is a quick way to get a deeper understanding without requiring to digest a whole book.

(At the link you'll find the archive with multiple size versions as well as a transcript, if you're rather visually oriented). Audio is not the perfect medium for this topic but Steve is working wonders to deal with this.

2024-07-20 22:44:22

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文