如何绕过Windows 10的CFG机制

前言

本文来源于我在2016年7月的研究结论,由于各种原因现在才能发布。2016年6月,Theori曾发表了一篇关于MS16-063中修补了的IE漏洞分析,文中发布的exploit则仅是针对Windows7上的IE 11版本,此外由于Windows 10采用了CFG机制所以无法对Windows 10机器进行利用。

而本文就描述了我是如何在Windows 10下绕过CFG并进行利用的。事实上我还发现了另一种方法,会在接下来的一篇文章中提到。

了解CFG

控制流保护(Control Flow Guard,CFG)是微软在Windows 8.1 update 3和Windows 10下实现的一个保护机制,用以保护在汇编层下的直接调用。趋势科技分享的一篇Windows 10如何实现CFG的分析文章很不错。虽说目前已有数种公开的CFG绕过方法,但是这些方法大多是针对CFG的实现算法,而我想从功能的薄弱点入手。

Theori在其博文中讲到由于CFG机制,无法成功在Windows 7上成功利用,接下来就让我们来细究一二,然后尝试绕过它。

Theori分享的利用代码在Windows 10的IE下执行,直到调用虚函数表后被重写。所以剩下的问题便是,我们如何利用任意读写来绕过CFG。

根据趋势科技的研究,函数LdrValidateUserCallTarget调用CFG验证函数是否有效使用了间接调用,如下图所示:

加载到EDX中的指针是验证bitmap的基本指针,在本例为:

之后经过验证的函数将其地址加载到ECX,以kernel32!VirtualProtectStub作为例子,那么地址则为:

接着地址向右偏移8位,用以加载存储着验证位(validation bit)的DWORD值:

函数地址右移3位,然后执行位测试,实质上对偏移地址进行0×20模操作。然后利用验证的bitmap对DWORD进行检测:

所以相关的位都在偏移地址0×14:

这也就是说它是有效的,VirtualProtect存在有效调用地址,然而它的参数也必须由攻击者提供,所以我们还得再接再厉。通常情况是在ROP链中完成,但所有不是从函数开始的字节都是无效的,因此解决方案是找到一个在被调用参数是可以控制的函数,且函数的功能可以给攻击者提供便利。

在Windows 10中利用

Theori提供的exploit,代码执行是以stack pivot重写TypedArray的虚函数表。由于排除掉其他可能性,细究TypedArray提供的函数还是很不错的,以下两个函数就比较有趣:

偏移地址分别为0x7c和0×188,他们能从javascript代码中直接调用,而且HasItem有个可以控制的参数,与此同时Subarray存在两个用户可控制的参数,然而问题是它们都不返回除布尔值之外的任何数据。之后的问题便是,我们该选择哪个函数来进行覆盖。

此外选择的函数必须提供相同数量的参数,否则在返回时会导致堆栈不平衡而引发异常。我要找的API应该是可以向堆栈加载一个指针用以覆盖返回地址,从而绕过CFG。

我找到的API为RtlCaptureContext,在kernel32.dll、kernelbase.dll和ntdll.dll中都有调用,这个API有一个指向CONTEXT结构的参数:

CONTEXT结构保存了转储的包含ESP的所有寄存器,此外输入值仅仅为一个可容纳数据的指向缓冲区的指针。如下为TypedArray对象的布局:

第一个DWORD值是虚函数表指针,其能够被覆盖偏移地址0x7c处的API RtlCaptureContext的地址,然后创建一个假的虚函数表。同时偏移地址0×20下的DWORD是TypedArray用以指向实际数据的指针:

由于它依旧可能泄漏缓冲区地址,我们就将其充当为RtlCaptureContext的参数。为了构造假的虚函数表,必须在偏移地址0x7c处创建一个指针指向ntdll!RtlCaptureContext,这意味着泄漏了RtlCaptureContext地址,也即ntdll.dll的地址也泄漏了。执行的默认路径需要使用一个指向jscript9.dll的指针的虚表地址:

从该指针向上迭代0×1000个字节搜索MZ头,之后查找到指向kernelbase.dll的导入表。然后使用同样的方法找到kernelbase.dll的基址,接着找到ntdll.dll的导入表指针并再次获得其基址,最后从导出函数中找到RtlCaptureContext。

尽管这个方法是有效的但是有个缺陷,如果系统中装了EMET,会触发来自jscript9.dll的代码崩溃,因为从PE头或导出表读取数据是不被允许的,为了绕过EMET我使用了另外的技术。

记住CFG会保护所有的间接调用,由于jscript9.dll的函数被CFG保护了,所以不能调用直接指向ntdll的函数。偏移地址0×10下就有一个这样的函数:

使用读操作,能通过以下函数找到指向ntdll.dll的指针:

通过一个指向ntdll.dll的指针得到RtlCaptureContext的地址,这一步可以不通过查找导出表而是通过搜索签名或者hash完成。RtlCaptureContext内容如下:

前0×30字节保持不变且看来相当的独特。如下所示当把他们整合在一起时,将其作为不受限制的哈希碰撞:

函数可以使用指向ntdll.dll的指针作为参数。

接着将其全都整合到一起:

缓冲区偏移地址0×200包含了来自RtlCaptureContext返回的结果:

从上面可以清楚地看出堆栈指针被泄漏,现在我们需要找到一个能执行控制的地址用以进行重写。注意堆栈顶部:

这就是当前函数的返回地址。运气不要太好,该偏移地址与其他简单函数将是相同的,所以可以进行写入并使其覆盖其返回地址,从而绕过CFG。

利用补充如下:

运行时显示EIP控制:

此外在偏移地址0×40和0×44的写入现在位于栈顶,其允许创建stack pivot于是获得ROP链,接下来就是使用POP EAX gadget,随后使用XCHG EAX,ESP gadget。

解决方案

然而微软表示,通过损坏堆栈上的返回地址以绕过CFG是一个已知的设计限制,因此无法领取任何种类的赏金,如下所示:

说了这么多,微软做了两个事情来解决这个问题,首先在Windows 10即将到来的版本中,将引进RFG机制(Return Flow Guard),防止通过损坏堆栈以获取执行控制的方式。其次便是在Windows 10的周年版发布中引入敏感的API的介绍,它仅保护微软Edge。虽然对于本例来说没有什么帮助,但是他能限制微软Edge中的RtlCaptureContext API。

Poc代码可以在这找到:https://github.com/MortenSchenk/RtlCaptureContext-CFG-Bypass

*参考来源:improsec,FB小编鸢尾编译,转载请注明来自FreeBuf.COM

原文发布于微信公众号 - FreeBuf(freebuf)

原文发表时间:2017-02-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏owent

Rust的第二次接触-写个小服务器程序

蛮久前入门了一下 Rust 语言。它的设计模型非常地吸引C/C++的开发者。但是学习语言嘛还是要练习一下,之前也用它给我们项目写了个命令行小工具。这回拿来写个小...

1.5K30
来自专栏Ldpe2G的个人博客

ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架

11630
来自专栏13blog.site

Mybatis-Generator生成Mapper文件中<if test="criteria.valid">的问题解答

写在前面 由于开源了项目的缘故,很多使用了My Blog项目的朋友遇到问题也都会联系我去解决,有的是把问题留在项目的issue里提出,有的是在我的私人博客里留言...

35960
来自专栏owent

初识Rust

虽然我主要使用C++,但是最近也想学点现代化的新语言。初步想的是从golang和Rust里先选一个。

22440
来自专栏性能与架构

Redis 新数据结构 - Streams

1. 为什么添加 Streams 数据流? Stream 数据流的使用越来越多,Redis 的作者 antirez 也在积极思考,如何让 redis 能够很好的...

43360
来自专栏技术博文

最简单的php导出excel文件方法

网上有很多php操作excel或其他文件的类库,也做的很完善。比如无比风骚的PHPExcel,官方网站:http://www.codeplex.com/PHPE...

75470
来自专栏Seebug漏洞平台

PWN学习之house of系列(一)

作者:Hcamael@知道创宇404实验室 准备一份house of系列的学习博文,在how2heap上包括下面这些: house of spirit hous...

450130
来自专栏Seebug漏洞平台

PWN学习之house of系列(一)

house of spirit是fastbin的一种利用方法,利用demo可参考: https://github.com/shellphish/how2heap...

1.2K130
来自专栏诸葛青云的专栏

C语言编程实例:清空对方应用程序

今天的文章跟大家讲一下,C语言中的文件操作——遍历文件夹和删除文件,以及如何应用这两个技能来写一个有趣的小程序,这篇文章涉及的知识点很少,也很简单,所以这篇文章...

21400
来自专栏C/C++基础

CVTE2017秋季校招笔试题回忆(C++后台岗)

2016.09.06晚参加了CVTEC++岗的在线笔试。笔试题型分为不定向选择题和编程题,总共27题。其中不定项选择题为25道,编程题2道。其特点是不定项选择题...

12610

扫码关注云+社区

领取腾讯云代金券