缓冲区溢出和返回libc攻击之间的区别
我想了解这两种类型的攻击之间的确切区别。根据我的阅读:
缓冲区溢出:它覆盖堆栈上的 ret 地址,以指向插入恶意代码的代码的另一部分。如此有效——这里我们需要修改程序的源代码才能实际执行攻击。
返回Libc-这里不修改源代码,而是使用C库提供的运行时函数调用(也就是说打开一个shell)。这里用于函数调用的参数也被传递到覆盖缓冲区中,结束在堆栈的 ret 部分之后。
以上描述准确吗?
另一个相关问题 - 是否有可能在不实际修改原始程序源代码的情况下进行缓冲区溢出攻击?可能如果我们编写一个新程序并允许它修改内存的某些部分(这是原始程序损坏的堆栈中的新 ret 地址)。话又说回来,我认为这可能是不可能的,因为内核中的进程之间提供了内存保护。
I want to comprehend the exact difference between these two types of attack. From what I have read:
Buffer Overflow: It overwrites the ret address on the stack to point to another section of the code where the malicious code is inserted. So effectively - here we need to modify the source code of the program to actually carry out the attack.
Return to Libc- Here instead of modifying the source code, run time function calls provided by the C library are used (to say open up a shell). Here the parameters used for the function call are also passed in the overwriting buffer, ending up after the ret part of the stack.
Is the above an accurate description ?
And another related question - would it be possible to have a buffer overflow attack without actually modifying the source code of the original program? Probably if we write a new program and allow that to modify certain sections of memory (which is the new ret address in the corrupted stack of the original program). Then again, I think this might not be possible due to memory protection offered between processes in the kernel.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在经典的缓冲区溢出漏洞利用中,溢出的堆栈缓冲区填充了要执行的机器代码(称为 shellcode,因为它通常调用 shell 进程)和新的返回地址。新的返回地址将被设计为指向溢出的堆栈缓冲区本身。显然,这需要知道或猜测受攻击进程中堆栈缓冲区的地址。
在那些日子里,进程的内存布局通常是高度确定性的 - 攻击者通常可以很好地预测堆栈缓冲区的位置(特别是如果他们确切地知道正在攻击的目标软件的版本)。为了在涉及一些猜测时提高成功的机会,活动 shellcode 之前通常会出现大量不执行任何有用操作的可执行机器代码 - 称为“NOP sled”或“NOP slip”,其中“NOP”是执行“无操作”的机器代码指令的典型名称。返回到 NOP 雪橇中任何位置的点都会达到预期的效果。
另一方面,“返回 libc”漏洞不会导致被劫持的进程直接返回到 shellcode。相反,它使进程一个接一个地返回到一系列库函数的开头。这些库函数可能会直接执行攻击者想要的操作,但更常见的是它们将用于间接执行攻击者的shellcode。
In the classic buffer overflow exploit, the stack buffer being overflowed was filled with both the machine code to be executed (called the shellcode, because it typically invoked a shell process) and the new return address. The new return address would be crafted to point back within the overflowed stack buffer itself. Obviously, this requires knowing or guessing the address of that stack buffer in the attacked process.
In those days, the memory layout of processes was typically highly deterministic - the location of the stack buffer could usually be predicted quite well by the attacker (particularly if they knew exactly which version of the target software was being attacked). To improve the chances of success when there was some guesswork involved, the active shellcode would often be preceeded by a large quantity of executable machine code that performed no useful operation - called a "NOP sled" or "NOP slide", where "NOP" is the typical name for a machine code instruction that performs "No Operation". Returning to a point anywhere in the the NOP sled would have the desired effect.
A "return-to-libc" exploit, on the other hand, does not cause the hijacked process to return directly to the shellcode. Instead, it causes the process to return, one by one, to the start of a chain of library functions. These library functions might directly perform the operations the attacker wants, but more commonly they will be used to indirectly execute the attacker's shellcode.
两种攻击共享覆盖 ret 地址的部分。正如上面的回复所示,您过去只是简单地返回到您编写的汇编代码。然后,该汇编代码将生成一个 root 用户 shell。
在这两种攻击中,您都不会“覆盖”源代码。从汇编的角度来看,源代码位于 .text 段中,并且始终(或至少我知道的一直)处于写保护状态。您过去所利用的方法是编写预先组装到内存段中的代码,然后跳转到该代码。该代码通常位于“堆栈段”中或附近,并且通过溢出您选择溢出的任何内容,您可以从那里的 ret 地址(比如说)重定向流量。其他攻击场所包括您之前创建并填充 shellcode 的环境变量;或者还有堆、函数指针或 PLT。如此插入的代码通常会使用 system() 调用来执行所需的操作 - 但为此,您需要能够在内存区域上“执行”(或者将您打算使用的重定位条目声明为可写)。
这两种攻击之间的区别在于,一旦内存基本上变得不可执行,a 类攻击(堆栈溢出)就几乎被搞砸了。当您编写时,尝试绕过这种类型的攻击是直接访问共享库函数 - 也就是说,您不再需要先将代码写入堆栈段或其他地方并在那里执行。不过,我相信 libc 类型的攻击现在也已大部分得到修复;我手边没有详细信息;也许我错了。
如果您想了解这些攻击现在是如何被挫败的,或者至少了解一些关键想法,请搜索“Smashing the Stack in 2011”(或 2010)开始。
The part of overwriting a ret address is shared between both attacks. As the above reply indicates, you used to simply return into assembly code you had written. This assembly code would then, say, spawn a root user shell.
In neither attack you would 'overwrite' the source code. Viewing it from an assembly perspective, the source code is in the .text segment and has always been (or at least all the time I know of) write-protected. What you used to take advantage of was to write code that you had priorly assembled into memory segments, and then jump to this code. The code was most typically located in or near the 'stack segment', and by overflowing whatever you choose to overlow, you'd re-direct traffic from the ret address (say) there. Other attack venues included an environmental variable you had priorly created and filled with your shellcode; or also the heap, or function pointers, or the PLT. The code so inserted would usually use the system() call to execute what was desired - but for this, you need to be able to 'execute' on memory areas (or have the relocation entries you intend to use being declared writable).
The difference between the two attacks is that once memory had been made largely non-executable, attack type a (stack overflow) was pretty much screwed. An attempt to bypass this type of attack was then, as you write, to instead access shared library functions directly - aka, you had no longer need to write your code first into the stack segment or elsewhere and execute it there. However, I believe libc type attacks are also largely patched by now; I don't have the details handy; and maybe I'm wrong.
If you'd like to see how any of these attacks are being thwarted these days, or at least read about some key ideas, google 'Smashing the Stack in 2011' (or 2010) to get started.
我想说缓冲区溢出是一类编程错误,返回libc是一种利用技术。最好不要将这些概念混在一起。
例如,您可以使用返回libc来利用缓冲区溢出漏洞。或者您可以使用其他技术,例如返回.text或返回shellcode。相反,您也可以使用返回libc来利用其他错误,例如格式字符串。
I would say buffer overflow is a class of programming error and return to libc is a exploitation technique. It is best not to mix the concepts together.
For example, you can use return to libc to exploit a buffer overflow vulnerability. Or you can use other techniques such as return to .text, or return to shellcode. Conversely, you can also use return to libc to exploit other bugs such as format string too.
实际上,在缓冲区溢出攻击中,您会在覆盖 ret 指针的同时插入恶意代码。您不需要为此修改任何内容,因此作为结论,我看不出提到的两种攻击之间的区别。
例如:
char* str[5];
辛 << str;
这是可以被分解的代码,如果用户插入大于 5 个字符的字符串,则堆栈上随后的所有内容都将被覆盖。由于 ret-ptr 在堆栈上“较低”,因此如果距离正确,您可以覆盖它。覆盖时的意图是让它指向输入的开头,在其中插入恶意(汇编器)代码,一旦调用 ret-ptr 并执行“跳转”,该代码就会执行。
Well actually, in a bufferoverflow attack, you insert the malicious code while overriding the ret pointer. You do not need to modify anything for this, so as a conclusion I cannot see the difference between both attacks mentioned.
For Example:
char* str[5];
cin << str;
This is code which can be exploided, if a user inserts a string larger than 5 chars, everything on the stack which follows will be overwritten. And due to the fact that the ret-ptr is "lower" on the stack, you can override it, if you get the distance right. Your intention while overriding is to let it point at the begining of your input, in which you inserted malicious (assembler) code, which would be executed as soon as the ret-ptr is called and the "jump" executed.