2

这可能与有关,但我不确定它是否在同一条船上。

所以我一直在重新阅读 Hacking: The Art of Exploitation 并且我对书中的一些 C 代码有疑问,这对我来说不太有意义:

让我们假设我们回到了 2000 年左右,并且我们真的没有堆栈 cookie 和 ASLR(也许我们有,但它还没有实现或没有普及),或者我们现在拥有的任何其他类型的保护 -一天。

他向我们展示了这段代码来利用一个简单的基于堆栈的溢出:

#include <stdlib.h>

char shellcode[] = "..." // omitted

unsigned long sp(void) 
{ __asm__("movl %esp, %eax); }

int main(int argc, char *argv[]) {
int i, offset;
long esp, ret, *addr_ptr;
char *buffer, *ptr;

offset = 0;
esp = sp();
ret = esp - offset;

// bunch of printfs here...

buffer = malloc(600);

ptr = buffer;
addr_ptr = (long *) ptr;
for(i = 0; i < 600; i+=4)
{ *(addr_ptr++) = ret; }

for(i = 0; i < 200; i++)
{ buffer[i] = '\x90'; }

ptr = buffer + 200;
for(i = 0; i < strlen(shellcode); i++)
{ *(ptr++) = shellcode[i]; }

buffer[600-1] = 0;

execl("./vuln", "vuln", buffer, 0);

free(buffer);

return 0;
}

所以他想要做的是获取 ESP 的地址并用该地址覆盖保存的 EIP,以便处理器将跳转到他在内存中的 NOP sled 并执行堆栈中的 shellcode。

我不明白的是,他如何使用他在当前调用它时从 sp() 获得的特定 ESP 值。

据我了解,堆栈看起来像这样的“东西”:

...
saved ebp <-- execl
saved eip
"./vuln"
"vuln"
buffer
0
*ptr <-- sp() returns this address?
*buffer
*addr_ptr
ret
esp
offset
i
saved ebp <-- main
saved eip
argc
argv
...

既然他在漏洞利用的早期调用了(我知道这是一个函数指针,所以我猜措辞不完全准确?) sp(),它不应该给他一个错误的 ESP 地址吗?即便如此,我也看不出他怎么能在这里使用这种技术,因为他永远不会在他的vuln程序中获得指向缓冲区顶部的 ESP。

谢谢。

4

3 回答 3

1

我看不出他怎么能在这里使用这种技术,因为他永远不会在他的vuln程序中获得指向缓冲区顶部的 ESP。

这本书我读的不多,但我想我已经弄清楚了。如下*buffer所示:

NOP sled | shellcode | Address of buffer in the exploit's stack frame

vulnstrcpy()进入自己的堆栈时,它无法检查边界并用漏洞利用buffer堆栈帧中缓冲区的起始地址覆盖自己的 EIP ,或者至少接近它的地址(因此是 NOP sled)。复制到 的栈帧的 NOP sled 和 shellcode是偶然的;不是他们跑的地方。sled 和 shellcode 必须小于预期的大小,否则保存的 EIP 将被 shellcode 而不是.vulnvulnbufferbuffer

vuln然后,当使用strcpy()on的任何部分buffer返回时,它会转到 NOP sled 并执行 shellcode。

重要的一点是在两个不同的地方buffer了两次

编辑:忽略这一点,我把自己弄糊涂了(尽管感谢您的接受!)。希望我也不会让您感到困惑,这就是我编写此编辑的原因。易受攻击的程序位于完全不同的虚拟内存空间中,因为它由操作系统在单独的进程中运行(或具有新映像的同一进程?随便)。因此vuln无法访问漏洞利用的堆栈堆。

ESP 诡计必须以某种方式猜测复制缓冲区中的 NOP 雪橇最终在vuln的堆栈中的位置。我个人希望偏移量比 0 大得多,因为与vuln相比,exploit 的堆栈非常小。

也就是说,我很确定vuln中仍然有两个 shellcode 副本(否则,它可能strcpy()来自什么?)。偏移量为 0,也许他正在运行存储在argv[]中的 shellcode ...?!? 在这种情况下,您仍然会遇到一个缓冲区中的地址指向另一个缓冲区中的 NOP 雪橇的情况,就像我原来的答案一样。不过我以前错了,所以如果这没有意义,请告诉我。

于 2013-07-17T15:56:02.840 回答
0

:) 我已经在这几天试图找出实际发生的事情。在这个过程中,我还发现了这篇文章。既然我对正在发生的事情有所了解,我想我应该分享我所理解的,以便像“我”这样的其他人也会发现这很有用。

unsigned long getesp()
{
__asm__("movl %esp, %eax");
}

这个函数实际上是用来猜测返回地址的。它返回我们的 shellcode 注入程序的 ESP 值,而不是易受攻击程序的 ESP 值。但是由于堆栈从几乎相同的地址开始(对于没有启用 ASLR 的系统)并且正如 aleph one 在他的文章中提到的那样“大多数程序在任何时候都不会将超过几百或几千个字节推入堆栈。因此通过知道堆栈从哪里开始,我们可以尝试猜测我们试图溢出的缓冲区将在哪里“,我们可以了解我们的 shellcode 应该在哪里。让我解释。

假设对于我们的测试程序,堆栈从 1000 开始。这个地址实际上是上面代码在执行时返回的。现在考虑我们的易受攻击的程序,假设我们尝试注入的缓冲区位于地址 970,返回地址存储在 1040。

[缓冲区 970][返回地址 1070]

好?现在缓冲区在前半部分用 NOPS 归档,然后是 shellcode,然后是返回地址。

[NOP SLED][SHELL_CODE][RETURN_ADDRESS]

让我们像这样填充它

NOPS [970-1010] SHELLCODE[1010-1050] RETURN_ADDRESS[1050-1070]

getesp() 返回的值给出了堆栈的位置。因此,如果我们用 getesp() 返回的 1000 重写返回地址,我们可以看到漏洞利用仍然有效,因为 1000 处的地址是用 nops 归档的。执行将下滑到 shellcode !

于 2014-06-18T19:32:36.593 回答
0

很大程度上取决于代码打算利用的特定操作系统。在不知道这一点的情况下,任何讨论都必须有点笼统[和我的猜测]。

一种可能性是您遗漏的“一堆printfs”中有一些重要的东西......

如果那里真的没有什么聪明的事情发生,我猜它试图利用的漏洞在execl(..)调用和/或操作系统中有效传递一个长(600 字节)命令行参数。那里的某个地方 [我猜] 一个子程序将为新进程设置环境,并且在此过程中将作为参数 ( buffer) 传入的 600 字节字符串复制到可能很小的 (ish ) 在新进程的堆栈上固定大小的缓冲区,并且 [大概] 用原始调用的堆栈指针的许多副本覆盖此“设置”函数的返回地址。当“命令行复制功能”返回时,它会从原来的副本中返回精心准备buffer的shellcode并执行。

(如果省略shellcode包含一个零字节...\x00...,那么这不可能是正在发生的事情,因为它会在设置命令行缓冲区时标记正在复制的字符串的结尾)。

于 2013-07-17T15:34:52.120 回答