要去看埃菲尔铁塔的顶
欢迎关注本人微博:t.cn/RGSLVUk
What's ?
SafeSEH机制是微软为了防止缓冲区溢出时覆盖SEH句柄而采用的新型内存安全机制,当SafeSEH开启时会再异常产生传递时首先校验SEH HANDLE的有效性(文件在编译时会被VS200*以上,在.data写入一张SEH HANDLE TABLE,在call 异常处理函数时对比这个表),
按照Alex 在 08 年的 Black Hat 大会上披露了 RtlIsValidHandler() 的细节SafeSEH 机制从 RtlDispatchException() 开始:
1. 如果异常处理链不在当前程序的栈中,则终止异常处理调用。
2. 如果异常处理函数的指针指向当前程序的栈中,则终止异常处理调用。(yesterday i end this)
3. 在前两项检查都通过后,调用 RtlIsValidHandler() 进行异常处理有效性检查。
BOOL RtlIsValidHandler( handler )
{
if (handler is in the loaded image) // 在加载模块的内存空间内
{
if (image has set the IMAGE_DLLCHARACTERISTICS_NO_SEH flag)
return FALSE; // 程序设置了忽略异常处理
if (image has a SafeSEH table) // 含有 SafeSEH 表说明程序启用了 SafeSEH
if (handler found in the table) // 异常处理函数地址在表中
return TRUE;
else
return FALSE;
if (image is a .NET assembly with the ILonly flag set)
return FALSE; // 包含 IL 标志的 .NET 中间语言程序
}
if (handler is on non-executable page) // 在不可执行页上
{
if (ExecuteDispatchEnable bit set in the process flags)
return TRUE; // DEP 关闭
else
raise ACCESS_VIOLATION; // 访问违例异常
}
if (handler is not in an image) // 在可执行页上,但在加载模块之外
{
if (ImageDispatchEnable bit set in the process flags)
return TRUE; // 允许加载模块内存空间外执行
else
return FALSE;
}
return TRUE; // 允许执行异常处理函数
}
基于上面的判断流程
若异常句柄(处理函数)在模块外 AND DEP 关闭 ,则 pass
若异常句柄(处理函数)在模块内 AND 异常句柄 在safe SEH TABLE中,则 pass
若异常句柄(处理函数)在模块内 AND image 不是 ILonly 则 pass
绕过 SafeSEH
方法一:覆盖函数返回地址。若攻击对象启用了 SafeSEH 但是 没有启用 GS 或者存在未受 GS 保护的函数,则可用这个方法。
方法二:攻击虚函数表来绕过 SafeSEH。
方法三:将 shellcode 部署在堆中以绕过 SafeSEH。
方法三:利用未启用 SafeSEH 的模块绕过 SafeSEH。(针对上述的 RtlIsValidHandler() 函数的第二种放行可能)
方法四:DEP 关闭时,可以利用加载模块之外的指令作为跳板(见后文示例)。
综合上面的,可以发现SafeSEH机制已经对SEH句柄进行了很严格的校验,校验函数中的
return false比较多,算是一个黑名单式的检验,但由于包含的情况不全面,所以pass的情况还是很多,接下来就是实验了。