2007年8月10日星期五

[Tips]SafeSEH笔记

by void
2007-08-10
http://www.ph4nt0m.org

Q: 如何在exploit里去触发SEH异常?
A: 让目标程序去读/写无效地址, 覆盖数据超出栈底.

Q: 如何找到需要覆盖的SEH?
A: 用测试串,如"aaaaaa..."覆盖stack导致异常,被od捕获,看SEH链,得到被覆盖的SEH处理程序的stack地址.

Q: 如何找跳转地址?
A: Ctrl+B/L 搜索5? 5? C3(pop reg/pop reg/retn)不一定找得到,
Ctrl+B/L搜索C3或者C2,Ctrl+↑/↓人工判定找.


ntdll!KiUserExceptionDispatcher()流程
VEH <-- winxp才有

SEH <-- win2000从这里开始

UEF 当程序被调试时,UnhandledExceptionFilter() SetUnhandledExceptionFilter()

ntdll!KiUserExceptionDispatcher 检查SEH handler过程:
1. 检查handler是否在线程TEB指定的Stack范围内(fs:[4]~fs:[8]),如果在其中,拒绝执行.
2. 检查handler是否在已加载模块列表(exe和dll), 如果handler不在这些模块地址范围内,执行.
3. 如果handler在模块地址范围内,开始检查已注册异常处理程序列表.
检查过程:
--------------
1) if((DLLCharacteristics&0xFF00) == 0x0400), 拒绝执行(No SEH);否则,继续检查.
2) Load Configuration Directory地址为0(即不存在),停止检查,执行.
Load Configuration Directory结构存在,继续检查:
+00h directory_size // 目录长度介于[0,0x48),停止检查,执行.
...
+40h handlers[] // SEH handler数组指针(元素是SEH handler RVA地址),if(handlers[]==0),停止检查,执行.
+44h handler_num // SEH handler数组元素个数,if(handler_num==0),停止检查,执行.

3) 然后开始逐个匹配,发现匹配,调用;没有发现匹配,拒绝调用.

针对Win2003/WinXP SP2对SEH handler(异常处理函数)地址的突破方法:
1. 不在stack里面, 在heap里.
对IE等浏览器,用js等heapspray分配堆,用堆内地址覆盖SEH handler.

2. 在已加载模块的范围外.
用代码页的跳转地址,比如0x7FFA1571(win2000/xp/2003 chs通用地址)

3. 在系统dll里面,且是该dll注册过的异常处理函数.
利用已注册的SEH handler,利用性不大.


od的safeseh插件的使用,用其分析已加载模块,得到如下结果:
/Safeseh ON 只能选已注册的SEH handler地址来跳.
/Safeseh OFF 可以选里面的地址(pop/pop/ret地址)来跳.
No SEH (DLLCharacteristics&0xFF00) == 0x0400, 不能跳.