<Oday安全 11.5利用未启用SafeSEH模块绕过SafeSEH>一节注记
来源:互联网 发布:nginx tomcat struts2 编辑:程序博客网 时间:2024/05/16 13:06
Oday安全一书的内容越往后越深奥,不得不做些注记备忘。
1.书P297 插图11.5.6写道__except函数地址根据EBP-4的值得出。这是目前为止,书中写的最含糊的地方,需要展开讨论一下。参考<软件调试>P726提及的vc编译器扩展后的异常处理结构:
(代码段1)
struct _EXCEPTION_REGISTRATION{ struct _EXCEPTION_REGISTRATION* prev;void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);struct scopetable_entry* scopetable;int trylevel;int _ebp;};当进入一个函数体时,经过一系列push指令(见代码段3)形成了这个结构。[EBP-4]正好是_EXCEPTION_REGISTRATION!trylevel域,这是一个数组索引---范围表的索引,数组地址由_EXCEPTION_REGISTRATION!scopetable域指向。范围表中每个数组项的结构为(参见<软件调试> P727):(代码段2)
struct scopetable_entry{ DWORD previousTryLevel; FARPROC lpfnFilter; //过滤表达式的地址 FARPROC lpfnHandler; //异常处理块的地址};有了这些预备知识后,来看下作者是如何由EBP-4推得__except函数地址:当书中示例程序执行完以下代码后:(代码段3)
00401020 55 push ebp00401021 8bec mov ebp,esp00401023 6afe push 0FFFFFFFEh00401025 6868224000 push offset callJump!__rtc_tzz+0x68 (00402268)0040102a 68f5174000 push offset callJump!_except_handler4 (004017f5)0040102f 64a100000000 mov eax,dword ptr fs:[00000000h]00401035 50 push eax栈内存分布如下:0:000> r ebpebp=0012ff6c0:000> dd [ebp] L10012ff6c 0012ff7c0:000> dd ebp-0x10 L80012ff5c 0012ffb0 004017f5 00402268 fffffffe0012ff6c 0012ff7c0x12ff5c+0xc处是tryLevel;栈0x12ff64处存放了scopetable的地址。观察scopetable数组的内容,0x402278处(当前只有这个地方的值和0401023处压入的0xFFFFFFFE匹配)为当前函数的scopetable_entry项,项中记录的过滤函数/异常处理块和windbg的!exchain输出相同。0:000> dd 00402268 L800402268 ffffffe0 00000000 ffffffb8 0000000000402278 fffffffe 004010c3 004010c9 000022c00:000> !exchain0012ff5c: callJump!_except_handler4+0 (004017f5) CRT scope 0, filter: callJump!test+a3 (004010c3) func: callJump!test+a9 (004010c9)
2.1.P296-P297,作者写道:"在Security Cookie+4的位置压入-2,在程序进入__try{}块后会修改为不同的值...我们的shellcode可能会被破坏"。根据<软件调试>P726的记述,__Exception_Registration!trylevel域在进出__try/__exception时会被编译器修改,这个位置正好位于ebp-4。我们的shellcode存放在栈上,溢出后可能会部分覆盖_EXCEPTION_REGISTRATION结构中的各个域,trylevel也可能被包含在其中。由于trylevel的值的易变性,这个位置不易存放shellcode,最好在在_EXCEPTION_REGISTRATION!scopetable的位置设置一段jmp短跳转,跳过trylevel中的shellcode。
2.2.感觉作者的这段话可能有笔误:"在Security Cookie+4的位置压入-2",我调试过程中发现Security Cookie位于ebp-0x1C的位置。下面是反汇编代码:
0401000 55 push ebp00401001 8bec mov ebp,esp00401003 6afe push 0FFFFFFFEh00401005 6828224000 push offset SafeSEHExe!__rtc_tzz+0x68 (00402228)0040100a 68f5164000 push offset SafeSEHExe!_except_handler4 (004016f5)0040100f 64a100000000 mov eax,dword ptr fs:[00000000h]00401015 50 push eax00401016 83ec14 sub esp,14h00401019 a100304000 mov eax,dword ptr [SafeSEHExe!__security_cookie (00403000)] <-----从此开始的3条指令,是计算本函数的Security Cookie值0040101e 3145f8 xor dword ptr [ebp-8],eax00401021 33c5 xor eax,ebp00401023 8945e4 mov dword ptr [ebp-1Ch],eax <-----Security Cookie保存的位置00401026 53 push ebx00401027 56 push esi00401028 57 push edi00401029 50 push eax0040102a 8d45f0 lea eax,[ebp-10h]0040102d 64a300000000 mov dword ptr fs:[00000000h],eax00401033 8965e8 mov dword ptr [ebp-18h],esp查看栈内存分布,Security Cookie与-2相差甚远,Security Cookie位于0x12ff58,-2位于0x12ff70:
0:000> ?? @ebpunsigned int 0x12ff740:000> ?? @ebp-0x1cunsigned int 0x12ff580:000> dd 0x12ff580012ff58 7e2a44b2 0012ff40 7c9c94f8 0012ffb00012ff68 004016f5 7e7899ee fffffffe 0012ffc0虽然,我的编译运行环境是:vs2005+WinXpsp3,编译器的版本比作者的略低,不过我感觉这并不是导致这种差异的根源。根据2.1节的讨论,我们已经确定__Exception_Registration!trylevel处存放了值-2,如果确如作者所说"在Security Cookie+4的位置压入-2",那security cookie正好侵占了__Exception_Registration!scopetable表。当然,读者可能认为这没关系啊,大不了可以让__Exception_Registration结构变成这样:
struct _EXCEPTION_REGISTRATION{ struct _EXCEPTION_REGISTRATION* prev;void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);struct scopetable_entry* scopetable;int Security Cookie;int trylevel;int _ebp;};这就更不合理了,编译器要针对是否启用GS选项维护同名的两个结构,兼容性堪忧了。3.绕过SafeSEH保护的执行流程。整个流程需要2个模块的通力合作:溢出发生在exe模块中,dll提供pop/pop/ret指令序列。
3.1.溢出发生时,__Exception_Registration!handler的内容被修改为dll提供的pop/pop/ret指令的地址;__Exception_Registration!prev被修改为一个短跳转指令EB 06
3.2.触发异常后,不管OS怎么一步步处理异常,最后都是以:
void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);的形式调用异常处理函数。如果未溢出,OS则以这样的形式条用ExceptHandle3;对于我们这的情形,OS则会去调用被修改的异常处理函数----这个函数的函数体很简单----只有pop/pop/ret 3条指令。虽然函数体是伪造的,但是函数的参数还是由OS传给它的(OS也不会关心谁是异常处理函数,它只管正确的传参数和调用)。需要注明的一点,大多数参考书列出的异常处理函数的接口都是这样的形式(<软件调试>P733):void (*handler)(PEXCEPTION_RECORD,void*,PCONTEXT,PEXCEPTION_RECORD);不过,可以确定的是第二个参数的类型void*就是对应我们的PEXCEPTION_REGISTRATION结构。3.3.开始执行pop/pop/ret指令流。由于这个函数体(不管其内容是啥,在OS看来这pop/pop/ret就是段函数体)中没有操作过堆栈,因此,目前函数栈内存从低往高依次保存了:1).OS call [异常处理函数]时压入的retAddr|2).OS 传递的参数1----PEXCEPTION_RECORD|3).OS传递的参数2----PEXCEPTION_REGISTRATION等。第一条pop指令从栈中弹出了retAddr;第二条指令从栈中弹出了PEXCEPTION_RECORD;当执行ret时,栈中只有参数2----PEXCEPTION_REGISTRATION了,这保存了异常发生时函数的堆栈---- 已经被我们用shellcode溢出的面目全非。执行完ret指令,eip将从异常发生时函数堆栈上取指令执行:执行的第一条指令就是从原__Exception_Registration!prev处取值,取到jmp 06;nop;nop(为什么要jmp 06?因为如果顺序执行完__Exception_Registration!prev处的代码后,必然会接着去执行__Exception_Registration!handler,这里保存的是dll中pop/pop/ret指令的地址,因此要跳过这些影响shellcode执行的代码)。
3.4.再往后就执行栈上其他的shellcode了.
(完)
参考: The need for a POP POP RET instruction sequence
0 0
- <Oday安全 11.5利用未启用SafeSEH模块绕过SafeSEH>一节注记
- 利用未启用SafeSEH模块绕过SafeSEH
- <Oday安全 11.6利用加载模块之外的地址绕过SafeSEH>一节注记---jmp [ebp+N] (上)
- <Oday安全 11.6利用加载模块之外的地址绕过SafeSEH>一节注记---jmp [ebp+N] (下)
- 突破SafeSEH机制之二——利用未启用SafeSEH模块绕过SafeSEH
- SafeSEH Exploit——利用未启用SafeSEH的DLL
- 突破SafeSEH机制之三——利用加载模块之外的地址绕过SafeSEH
- 利用加载模块之外的地址绕过SafeSEH
- 突破SafeSEH机制之一——利用堆绕过SafeSEH
- <Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess>一节注记(上)
- <Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess>一节注记(下)
- 利用Adobe Flash Player ActiveX 控件绕过SafeSEH
- 利用Adobe Flash Player ActiveX控件绕过SafeSEH
- 简单演示Exploit SEH原理(未开启SafeSEH模块)
- SafeSEH基本概念+ 从堆区绕过SafeSEH学习
- SafeSEH原理及绕过技术浅析
- SafeSEH原理及绕过技术浅析
- 利用 Adobe Flash Player ActiveX 控件绕过 SafeSEH(问题及解决方法)
- 你不得不知道的js之作用域链与闭包
- C语言中常见的内存错误
- android 时区时间转换
- JavaScript中的document.cookie的使用
- sqlite3_get_table 的函数使用
- <Oday安全 11.5利用未启用SafeSEH模块绕过SafeSEH>一节注记
- Linux终端用vim打开文件,中文显示乱码
- 【codeforces 550E】Brackets in Implications
- 简单的推荐系统搭建--Python(pearson,欧几里得相似度)
- pywin32下载链接及安装报错问题解决链接
- SSH框架之Hibernate的一对一映射
- 约瑟夫环
- sublime常用快捷键
- 菜单实现对话框