为什么JMP ESP而不是直接跳入堆栈

信息安全 开发 脆弱性 缓冲区溢出
2021-09-07 20:39:39

首先,如果这篇文章不完全适合这里,或者可能更适合 RE,我很抱歉。如有必要,我们可以移动它。

所以,我正在阅读这篇关于vulnserver漏洞利用的文章(对于那些不知道它的人,vulnserver 是一个在设计时考虑到缺陷的程序,这是为了练习利用技术)

在某个时刻,它说:

在这一步中,我们必须检查寄存器和堆栈。我们必须找到一种方法来跳转到我们的缓冲区来执行我们的代码。ESP 指向缓冲区 C 部分的开头。我们必须找到一条 JMP ESP 或 CALL ESP 指令。不要忘记,地址不能包含坏字符!

这是有道理的,但是;既然我们控制了EIP,直接跳入堆栈是不是不可能也更容易?(我们当然假设 ASLR 和 DEP 被禁用)。主要是因为:

  1. 他怎么知道 ESP 指向他的 shellcode?为什么 ESP 准确地指向那里?它不应该指向他的 shellcode 的结尾吗?

  2. 这应该如何通过重新启动或在不同的计算机上工作?

谢谢。

2个回答

您的漏洞利用负载最终会出现在堆栈上,因为您溢出了堆栈上的缓冲区,这也是您控制返回地址的方式。

ESP 直接指向有效负载的开头(在ret您正在攻击的函数中执行之后),因为您将有效负载放在覆盖堆栈上返回地址的 4 个字节之后。 ret将 4(或 8)个字节弹出到 EIP 中,让 ESP 指向紧随其后的有效负载。

但是你不知道 ESP 在那一点上会有什么价值,因为堆栈 ASLR 以及导致这一点的不同调用堆栈深度可能会改变地址。 所以你不能硬编码一个正确的返回地址

但是,如果在进程内存中的固定(非 ASLRed)地址处有字节解码为jmp esp或任何位置,您可以call esp将该地址硬编码为您的漏洞利用中的返回地址。执行将到那里,然后到您的有效负载。

事实上经常出现这种情况:一些 DLL 没有为其代码启用 ASLR,并且主可执行文件的代码也可能没有经过 ASLRed。

所有代码的代码 ASLR都会阻止jmp esp攻击,除非攻击者可以导致目标进程泄漏地址。

请注意,对于 64 位代码,您不太可能使用jmp rsp基于字符串的缓冲区溢出,因为代码地址将包含一些前导0字节


因此,jmp esp与重复猜测返回地址(使用非常大的 NOP sled)相比,它为您提供了更可靠的利用。

每次你错了,重复猜测都会使目标进程崩溃,但是jmp esp第一次尝试就可以给你很大的成功机会。这将避免留下崩溃日志。它还可以击败一个入侵检测系统,该系统会寻找崩溃的服务器进程并阻止来自您的 IP 地址或类似地址的连接。


请注意,当程序正常执行时,您要查找的 2 字节指令可以作为另一条指令的一部分出现,或者作为静态数据(尤其是只读数据通常在可执行页面中)出现。所以你只需要搜索2字节的序列,而不是jmp esp反汇编程序。编译器永远不会使用jmp esp,因此您不会以那种方式找到它。


更一般地说,任何以任何寄存器中的缓冲区指针结尾的函数(例如,来自 amemcpy或特别是)都可以通过查找指令strcpy来允许ret2reg攻击。jmp eax

这可以在 64 位模式下工作,其中地址有一些高位零字节;如果strcpy's 的尾随零为您写入那个高地址字节,则您的漏洞利用字符串的结尾可能是覆盖堆栈上的返回地址的非零地址字节。

在这种情况下,可执行有效负载将位于返回地址之前,位于缓冲区中函数留下寄存器指向的位置。(如果寄存器中有任何有用的指向缓冲区的指针,通常是缓冲区的开头)。

缓冲区溢出后,ESP 具有 shellcode。您可以在免疫中验证它,EIP 必须指向 ESP。我的理解是在漏洞利用之前,系统 DLL 应该使用 ESP,具体取决于何时调用 DLL。

但是缓冲区溢出后,EIP 不知道该指向哪里。请注意,我们传递给 EIP 的 4 个字节可以是任何 [jmp ESP] 地址。

所以它是这样的 -

  1. 正好溢出缓冲区直到 EIP
  2. 将 [jmp ESP] 地址传递给 EIP
  3. ESP 中的存储值被执行(NOPs + Shellcode)

我在 [jmp ESP] 处编写了一个漏洞利用程序并使用了地址变体,并且每次我都可以利用该漏洞。

这是exploit.py,注意我使用的是RPCRT dll。但我们也可以使用 shell32.dll 和其他系统 dll。

https://github.com/shankar-ray/Exploit-Development/blob/master/exploit-py

我正在使用带有一些额外 NOP 的 shell 绑定 shellcode。

顺便说一句,如果操作系统有某种保护,或者编译器在编译原始 src 代码时添加了一些保护。这将成为寻找 shellcode 位置的寻宝游戏。然后我们需要使用几个跳转来到达 shellcode。

希望有帮助!