我要引用的代码位于:链接到代码

我读到缓冲区溢出漏洞利用了一个看起来像这样的缓冲区:

| NOP SLED | SHELLCODE | REPEATED RETURN ADDRESS |


据我了解,当缓冲区作为函数参数放入堆栈并覆盖函数的返回地址时,就会发生漏洞利用。我还理解重复的返回地址指向堆栈上同一缓冲区中的NOP底座。

我不明白的是:


为什么返回地址必须指向同一缓冲区中的shellcode?有人告诉我,我无法将返回地址指向shellcode数组(与同一缓冲区中的NOP底座中的地址相对),因为不同的进程无法访问彼此的内存或类似的东西。如果有人可以向我解释这一点,我会很乐意。
缓冲区中的返回地址如何与原始地址完美对齐,因此ret命令将读取正确的地址,而不是从中间读取。
我指的是缓冲区上重复的返回命令将覆盖用call指令压入堆栈的原始返回命令。为什么覆盖寄信人地址与原始地址完全一致?


评论

您确实知道堆栈向哪个方向增长?从Wiley获取《 Shellcoder手册》以获取详细说明。

我做。它长大(朝着较低的内存地址)。

您必须阅读-Aleph1粉碎堆栈以获得乐趣和获利。这是经典...

#1 楼


为什么返回地址必须指向同一缓冲区中的shellcode?


它不是,但是通常,shellcode和返回地址都在同时,因此它们被卡在一起。如果您的漏洞利用可以单独分发,则可以将它们分开。但是,由于返回地址是该进程的本地地址,因此它们对于所使用的进程都是必需的。一旦shellcode获得控制权,它当然可以跨越进程边界。堆栈图像如下所示:缓冲区变量,其他变量,返回地址。将shellcode放入缓冲区,如果需要,其他变量将被nop sled覆盖,然后修改返回地址。


缓冲区中的返回地址如何完美与原始地址对齐,因此ret命令将读取正确的地址,而不是从中间读取地址,例如


在32位模式下,堆栈对齐为4个字节,变量放在4字节对齐的地址上,并对其大小进行填充以对齐4字节的倍数,因此,一个字节的char在堆栈中占用4个字节,一个121字节的缓冲区将在堆栈中占用124个字节,等。
漏洞利用编写者要做的就是填充shellcode + nop底座,直到它对齐到4字节的倍数,然后放置返回地址。

#2 楼

如果我正确地理解了您的第一个问题,那么我认为您和告诉您的任何人之间都存在脱节。没有限制基于缓冲区处于同一进程中,至少没有关于返回值的限制。您绝对可以将返回地址指向shellcode的开头。这完全取决于您。

返回NOP雪橇的更好原因既是惯例,也是一个好习惯。在某些示例中,您不知道代码最终将在哪里结束,NOP底座有助于“捕获”重定向的EIP。由于NOP不执行任何操作,因此它为您提供更大的缓冲区和更大的捕获代码的可能性。正如您所链接的讨论中的评论之一所言,这不是一种非常强大的剥削形式。

第二个问题更为笼统。我没有本书的复印件,但弄清楚将返回地址写入缓冲区的程度实际上是反复试验。假设崩溃是可靠的,则可以将缓冲区从120 A更改为AAAABBBBCCCCDDDDEEEE ...等。程序崩溃时,您将看到EIP中有什么垃圾,您可以使用该值来计算数据被覆盖的偏移量。例如,如果程序终止时的EIP包含44444444, ,这意味着RET指令将DDDD段从堆栈中拉出。因此,当您进行最终利用时,您将知道它是12个字节,直到保存的EIP被覆盖在堆栈上。比这更人为设计的,Metasploit有很多很棒的脚本来简化这一过程。 pattern_create将创建一个长度唯一的模式,pattern_offset将使用该模式的长度和一些子字符串,并告诉您它的长度。

#3 楼

关于第一个问题,没有什么可以阻止您将shellcode放在该进程的可执行内存中的任何位置。例如,一种常见的做法是(说实话)将shellcode放在某个环境变量中,因为(在没有ASLR的情况下)可以精确计算它们的地址。在这种情况下,您不必猜测返回地址,而只需计算shellcode在环境中的地址,然后将该地址用作返回地址即可。

此技巧的另一个好处是不受缓冲区大小的限制。但是,另一方面,它显然仅适用于本地漏洞利用。

shellcode经常位于覆盖原始返回地址的同一个缓冲区中的原因是,它在一开始就很容易解释。