首先,请阅读以下内容:
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->Handler
shellcode?
这是一个 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/
比我能更好地解释最后一部分。