首先,请阅读以下内容:
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],这可能是一个攻击向量。
EBX已0在开头设置为RtlDispatchException它以前包含PEXCEPTION_RECORD.
ESI是PEXCEPTION_RECORD并且EDI是PCONTEXT。
清零寄存器到底是怎么回事,为什么它们会破坏 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/
比我能更好地解释最后一部分。