C语言 导致安全泄漏的缓冲区溢出示例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3291936/
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
Example of a buffer overflow leading to a security leak
提问by Tomaka17
I read many articles about unsafe functions like strcpy, memcpy, etc. which may lead to security problems when processing external data, like the content of a file or data coming from sockets. This may sound stupid, but I wrote a vulnerable program but I did not manage to "hack" it.
我阅读了很多关于不安全函数的文章,如 strcpy、memcpy 等,这些函数在处理外部数据(如文件内容或来自套接字的数据)时可能会导致安全问题。这听起来可能很愚蠢,但我编写了一个易受攻击的程序,但我没有设法“破解”它。
I understand the problem of buffer overflow. Take this example code:
我了解缓冲区溢出的问题。以这个示例代码为例:
int main() {
char buffer[1];
int var = 0;
scan("%s", &buffer);
printf("var = 0x%x\n", var);
return 0;
}
When I execute the program and type "abcde", the program outputs 0x65646362 which is "edcb" in hexadecimal + little-endian. However I read that you could modify the eip value that was pushed on the stack in order to make the program execute some unwanted code (eg. right before a call to the system() function).
当我执行程序并输入“abcde”时,程序输出 0x65646362,它是十六进制 + 小端的“edcb”。但是我读到您可以修改压入堆栈的 eip 值,以使程序执行一些不需要的代码(例如,在调用 system() 函数之前)。
However the function's assembly starts like this:
然而,函数的程序集是这样开始的:
push %ebp
mov %ebp, %esp
and int main() {
char buffer[1];
int var = 0;
var = SecurityCheck();
scan("%s", &buffer);
if (var != 0)
GrantAccess();
else
DenyAccess()
}
xfffffff0, %esp
sub printf( string );
x20, %esp
Since the value of %esp is random at the start of the function and because of this "and", there seems to be no reliable way to write a precise value into the pushed eip value.
由于 %esp 的值在函数开始时是随机的,并且由于这个“和”,似乎没有可靠的方法将精确值写入推送的 eip 值。
Moreover, I read that it was possible to execute the code you wrote in the buffer (here the buffer is only 1 byte long, but in reality it would be large enough to store some code) but what value would you give to eip in order to do so (considering the location of the buffer is random)?
此外,我读到可以执行您在缓冲区中编写的代码(这里的缓冲区只有 1 个字节长,但实际上它足以存储一些代码)但是您会按顺序给 eip 什么值这样做(考虑到缓冲区的位置是随机的)?
So why are developpers so worried about security problems (except that the program could crash) ? Do you have an example of a vulnerable program and how to "hack" it to execute unwanted code? I tried this on linux, is Windows less safe?
那么为什么开发人员如此担心安全问题(除了程序可能会崩溃)?您是否有一个易受攻击的程序示例以及如何“破解”它以执行不需要的代码?我在 linux 上试过这个,Windows 不太安全吗?
采纳答案by Tomaka17
Read the excellent article by Aleph One: Smashing the Stack for Fun and Profit.
阅读 Aleph One 的优秀文章:Smashing the Stack for Fun and Profit。
回答by torak
Well for one thing, don't under estimate the hazards associated with being able to unreliably place a value inside EIP. If an exploit works one in 16 times, and the service it is attacking automatically restarts, like many web applications, then an attacker that fails when trying to get access can always try, try again.
一方面,不要低估与能够不可靠地在 EIP 中放置值相关的危害。如果一个漏洞利用 16 次成功,并且它正在攻击的服务自动重新启动,就像许多 Web 应用程序一样,那么在尝试获取访问权限时失败的攻击者可以随时尝试,再试一次。
Also in a lot of cases the value of ESP is less random than you think. For starters on a 32-bit system it is nearly always a multiple of four. That means that the extra padding offered by the and $0xfffffff0, %espinstruction will be either 0, 4, 8 or 12 bytes. That means that it is possible to just repeat the value that is to be written into the return EIP four times to cover all possible offsets to the address of return EIP.
此外,在很多情况下,ESP 的值没有您想象的那么随机。对于 32 位系统上的初学者来说,它几乎总是四的倍数。这意味着and $0xfffffff0, %esp指令提供的额外填充将为 0、4、8或 12 个字节。这意味着可以将要写入返回 EIP 的值重复四次,以覆盖返回 EIP 地址的所有可能偏移量。
There are actually much more aggressive stack protection / buffer overflow detectionmechanisms around. However, there are ways and means around even these.
实际上有更积极的堆栈保护/缓冲区溢出检测机制。然而,即使是这些,也有办法。
Also, for an example of where this sort of thing can be dangerous, consider if the value of varwas important to you logic as in the following toy example.
此外,对于此类事情可能存在危险的示例,请考虑 的值var是否对您的逻辑很重要,如下面的玩具示例所示。
回答by R.. GitHub STOP HELPING ICE
Further you don't have to overwrite EIP with a pointer to something in your string. For example you could overwrite it with a pointer to system()and overwrite the next word with a pointer to /bin/shat a fixed location in the program image.
此外,您不必使用指向字符串中某些内容的指针覆盖 EIP。例如,您可以使用指向的指针覆盖它,system()并使用指向/bin/sh程序映像中固定位置的指针覆盖下一个单词。
Edit: Note that systemuses the PATH(actually it runs the command via a shell), so "sh"would be just as good; thus, any English word ending in "sh" at the end of a string provides the argument you need.
编辑:请注意,system使用PATH(实际上是通过 shell 运行命令),所以"sh"也一样好;因此,任何在字符串末尾以“sh”结尾的英语单词都会提供您需要的参数。
回答by ninjalj
As mentioned in other answers, absolute reliability is not always essential for the attack to succeed. Applications that restart automatically are an example. Locally exploitable buffer overflows on suid programs would be another. And there's the NOP sled technique to increase chances of successful exploitation, put a lot of NOPs before your shellcode so you have a much better chance to correctly guess the "start" of your shellcode.
正如其他答案中提到的,绝对的可靠性对于攻击的成功并不总是必不可少的。自动重启的应用程序就是一个例子。suid 程序上的本地可利用缓冲区溢出将是另一个。还有 NOP sled 技术可以增加成功利用的机会,在你的 shellcode 之前放置很多 NOP,这样你就有更好的机会正确猜测 shellcode 的“开始”。
There are many more techniques for increasing the reliability of attacks. On Windows, back in the day, many exploits overwrote the return address with the address of a "jmp %esp" located somewhere in the program (trampoline).
还有更多的技术可以提高攻击的可靠性。在 Windows 上,回到过去,许多漏洞利用位于程序(trampoline)中某处的“jmp %esp”地址覆盖了返回地址。
"Insecure programming by example" had a nice trick for Linux. Clean your environment and put your shellcode in an environment variable. Back in the day, this would lead to a predictable address near the top of the stack.
“不安全的编程示例”对 Linux 有一个很好的技巧。清理你的环境并将你的 shellcode 放在一个环境变量中。回到过去,这将导致在堆栈顶部附近有一个可预测的地址。
And there are also variants like return-into-libc and return-oriented programming.
还有一些变体,如 return-into-libc 和面向返回的编程。
There was even an article on Phrack on how to exploit 1-byte stack overflows (meaning the buffer was overrun by only one byte) (btw, 1-byte heap overflows are also exploitable in the vast majority of cases, barring protections).
甚至在 Phrack 上有一篇关于如何利用 1 字节堆栈溢出(意味着缓冲区仅溢出一个字节)的文章(顺便说一句,1 字节堆溢出在绝大多数情况下也是可利用的,除非有保护措施)。
To sum up, it's not that developers are paranoid, there are lots of ways to exploit even the strangest cases, and remember:
总而言之,并不是开发人员偏执,即使是最奇怪的情况也有很多方法可以利用,请记住:
- A program is of good quality when it does what it is supposed to do.
- A program is secure when it does what it is supposed to do, and nothing more.
- 当一个程序完成它应该做的事情时,它就具有良好的质量。
- 一个程序在做它应该做的事情时是安全的,仅此而已。
回答by David Gelhar
A classic example of an actual exploit based on buffer overruns is the Morris Wormof 1988.
基于缓冲区溢出的实际漏洞利用的一个经典示例是1988 年的莫里斯蠕虫。
回答by eruciform
Here's a windows version and tutorial:
这是一个 Windows 版本和教程:
http://www.codeproject.com/KB/winsdk/CodeInject.aspx
http://www.codeproject.com/KB/winsdk/CodeInject.aspx
The general case I was always warned about was:
我一直被警告的一般情况是:
##代码##Because the user can provide a "%n"in there, which allows you to insert anything you want into memory. All you need to do is find the memory offset for a system call, pass a few "%n"'s and junk characters, and thus insert the memory address onto the stack where the return vector would normally be. Voila -- insert any code you like.
因为用户可以"%n"在那里提供一个,它允许你将任何你想要的东西插入内存。您需要做的就是找到系统调用的内存偏移量,传递一些"%n"'s 和垃圾字符,然后将内存地址插入到通常返回向量所在的堆栈中。瞧——插入任何你喜欢的代码。

