为什么和何时我们需要 SEH 来处理缓冲区溢出

逆向工程 视窗 x86 免疫调试器 缓冲区溢出
2021-06-16 08:37:45

在我们大学的课程中,我们最近从标准缓冲区溢出转向基于 SEH 的。

多亏了一些不错的教程,我的漏洞利用已经准备好并可以工作,尽管我仍然不确定我是否完全理解,何时以及为什么我们需要 SEH 缓冲区溢出。

到目前为止,我的理解是,如果源代码中没有明确的异常处理程序,每个线程都会自动获得一个,另外还会有特定的处理程序。

对于易受 SEH BOF 攻击的程序,缓冲区溢出将导致例如 Immunity 调试器在出现异常时暂停程序。只有在异常传递给程序后,EIP寄存器才会被恶意缓冲区覆盖。

问题 1:

为什么不是每个程序都会发生这种情况,因为在任何情况下都应该有一个自动异常处理程序?

在传递异常EIP并被ESP覆盖后,使用我的缓冲区中的值,但其他寄存器被清零(在我的示例中为EAX, EBX, ESI& EDI)。所以我可以控制EIPand ESP,但是教程提到它没有用,因为寄存器被清零。然而,他们从来没有解释为什么归零的寄存器是问题——所以这是我第二个缺乏理解的地方。

问题2:

清零寄存器到底是怎么回事,为什么它们会破坏 shellcode 执行?

现在我们还覆盖了 NSEH 和 SEH 记录,并且使用一种模式可以计算出覆盖它们的确切偏移量。然后是引用一些POP POP RET必须到达ESP + 8.

加上最终又一次跳跃。

问题 3:

为什么我需要 POP POP RET 和最后一跳?


我有漏洞利用,可以像这样提交,但在没有真正了解发生了什么的情况下感觉非常不令人满意和毫无意义。我最近才开始研究低级的东西,还有很多东西要学,所以我非常感谢每一个帮助。

1个回答

首先,请阅读以下内容:

https://www.blackhat.com/presentations/bh-asia-03/bh-asia-03-litchfield.pdf

这几乎就是这一切的开始。

SEH 缓冲区溢出是一种特定的堆栈溢出,它针对EXCEPTION_REGISTRATION_RECORD位于堆栈下方任意距离的位置。

为什么不是每个程序都会发生这种情况,因为在任何情况下都应该有一个自动异常处理程序?

是的,因为您无法在 Windows 上真正禁用 SEH。如果您的缓冲区溢出可以达到EXCEPTION_REGISTRATION_RECORD并且您可以触发异常。

传递异常后,EIP 和 ESP 被覆盖,使用我的缓冲区中的值,但其他寄存器被清零(在我的示例中为 EAX、EBX、ESI 和 EDI)。

从我的ntdll.dll版本10.0.17134.254...

在被XOR……之前

EAX持有一个指向当前的指针,EXCEPTION_REGISTRATION_RECORD所以如果你EXCEPTION_REGISTRATION_RECORD->Next用有效载荷地址覆盖并将 设置为EXCEPTION_REGISTRATION_RECORD->Handler执行的随机指令JMP/CALL [EAX],这可能是一个攻击向量。

EBX0在开头设置为RtlDispatchException它以前包含PEXCEPTION_RECORD.

ESIPEXCEPTION_RECORD并且EDIPCONTEXT

清零寄存器到底是怎么回事,为什么它们会破坏 shellcode 执行?

他们不一定。在我们开始执行处理程序之前,我们必须经历ntdll!KiDispatchUserException->ntdll!RtlDispatchException无论如何最终会覆盖所有寄存器。

这就是内核CONTEXT在返回用户模式之前将它们保存在结构中的原因

这种利用不是简单的EIP劫持。在异常之后我们开始执行之前,堆栈和寄存器发生了很大的变化。

为什么我需要 POP POP RET 和最后一跳?

你的意思是为什么不直接设置EXCEPTION_REGISTRATION_RECORD->Handlershellcode?

这是一个 ROP 小工具,用于将执行重定向到ESP+8. 如果您在漏洞利用中做到了这一点,那么ESP+8您可以控制at 的数据,但您可能不一定提前知道它在哪里。

其次,在异常和处理程序执行之间有许多健全性和安全性检查。如果其中任何一个失败,程序将在处理程序运行之前终止。这些包括什么取决于您所针对的 Windows 版本。SafeSEH 就是其中之一。很简单,它会根据白名单验证处理程序地址,但无法验证未使用 SafeSEH 编译的模块中的处理程序。因此,如果 POP/POP/RET 来自没有 SafeSEH 加载和编译的模块,ntdll 无法确定它是否是恶意的。

加上最终又一次跳跃。

这是最好的部分!

因为ESP+8是我们要登陆的地方,所以我们可以把shellcode放在这里。除了它EXCEPTION_REGISTRATION_RECORD是我们需要完好无损的,以便EXCEPTION_REGISTRATION_RECORD->Handler使漏洞利用的第一部分工作。

幸运的是,EXCEPTION_REGISTRATION_RECORD->Prev(您拥有的NSEH)代表 POP/POP/RET 将返回的 shellcode 的前 4 个字节。

x86 中的短跳转可以仅用 2 个字节进行编码。所以这个最后的跳转跳过了 6 个字节,NSEH所以它可以保持有效以便漏洞利用工作。

这个博客:

https://dkalemis.wordpress.com/2010/10/27/the-need-for-a-pop-pop-ret-instruction-sequence/

比我能更好地解释最后一部分。