正好在Google搜到了这篇文章,就打算自己翻译一下,也不清楚国内是否有人已经翻译过了。作者是Pwn2Own 2010的获奖者来自荷兰的皮特·维莱格登希尔(Peter Vreugdenhil)。
2010的Pwn2Own是第一次公开亮相的攻破有ASLR+DEP保护的IE浏览器,所以也是我比较关注的一点。当然了就目前(2016)来说,这些都已经是漏洞利用的标配了。所以是一次考古性质的翻译。
ps:我是根据对技术的理解去翻译的,很多地方都有删改,要求精准的可以去看原文。
http://vreugdenhilresearch.nl/Pwn2Own-2010-Windows7-InternetExplorer8.pdf

我决定写一篇关于我在Windows7下攻破有DEP和ASLR保护的IE8浏览器的技术文章。

整个利用过程分为两大步骤

第一步是找出一个确定的dll文件的加载基地址,然后在第二步中会使用到第一步中得到信息来使用一些ret2libc技术去bypass DEP,然后劫持流程去执行shellcode。我暂时还不能公开详细的漏洞细节,但是等微软修补过后我会逐步公开细节的。就像我前面说的那样,我使用了两个exp才实现最后的任意代码执行的结果。

在第一步中,为了获得ie浏览器中一个dll模块加载的基地址,我使用了一个堆溢出覆写了一个UTF8 String(对象?)的尾部结束符(\x00\x00),这样当我读这个字符串的时候就可以读到下一个对象的虚表指针了。当然了,下一个对象也是我精心布置好的。实现这个想法花了我好几天的时间,最终才实现了稳定的利用。

我画一个堆内存的示意图,

黄色的内存是发生溢出的堆块。

绿色的内存是我们分配的Unicode String。其中结尾符\x00\x00由亮绿色表示。

红色的内存是我们精心分配的对象,其中亮红色表示对象的虚表指针。

虽然看着好像很简单,但实际实现却有很多困难。这需要一些技巧才能把内存布局成我们想要的形式。首要的前提是浏览器要存在着一个可以控制的堆溢出,并且我们的这些操作不能让浏览器崩溃掉。然而,经过了一番努力之后,我成功的构造了想要的布局,而且可靠性很高。然后我触发了堆溢出,覆盖了字符串结尾的字符。这样字符串就不再以\x00\x00作为结尾了。如果我们接下来用js函数去读取这个字符串的内容的话,那么就会一直读到下一个\x00\x00为止。这样js函数就读到了下一个对象的虚表地址。虚表地址有什么用呢?虚表在编译时就已经编译到了dll模块中,就是说虚表的地址到模块起始的偏移是确定的。所以根据虚表地址就可以计算出来对象所处的dll模块的基地址。这个信息可以用来编写一个绕过DEP的exp(实质上是bypass ASLR)。如果我对写入溢出的数据拥有完全控制的话,覆写下一对象的虚表就很容易了。但是如果我对溢出数据的控制受到限制的话,我就不能确保可以覆写虚表指针了。

第二步就是想办法绕过DEP的保护了,几个月前,我写了一个绕过IE8下DEP保护的exp,使用的技术是堆喷射+ROP。事实上是混合使用了堆喷射和对象调用伪造,但是我并不确定我是不是第一个使用这种技术的人。在我调试一个IE浏览器的UAF漏洞时,我注意到大堆块的分配是可以预测的。但是不是精准的预测,而是我发现分配地址的最后两个字节总是相同的。在XP系统上大于100字节就会是可预测的。这样一来我们就足够去做堆喷射,并且很有可能猜到喷射到的地址。

举一个例子,下面的代码将不断的分配一些填充有固定内容的堆。这个堆的分配地址应该是开始于0xZZZZZY20的,其中Z的值是随机的,Y则只能为0/4/8/C。因为我分配的单元大小是0x200个字节。

 heap = new heapLib.ie(0x20000);
var heapspray = unescape("%u4141%u4242");
while(heapspray.length < 0x200) heapspray += unescape("%u4444");
var heapblock = heapspray;
while(heapblock.length < 0x40000) heapblock += heapblock;
finalspray = heapblock.substring(2, 0x40000 - 0x21);
for(var i = 0; i < 500; i++)
{
heap.alloc(finalspray);
}

这段代码的执行结果可能是这个样子的

Heap alloc size(0x7ffc0) allocated at 063d0020

Heap alloc size(0x7ffc0) allocated at 06450020

Heap alloc size(0x7ffc0) allocated at 064d0020

Heap alloc size(0x7ffc0) allocated at 06550020

Heap alloc size(0x7ffc0) allocated at 065d0020

Heap alloc size(0x7ffc0) allocated at 06650020

Heap alloc size(0x7ffc0) allocated at 066d0020

如上可见,你得到了堆中彼此相邻的块。

上面例子中的分配大小对于你来说是没有用的,因为这个大小取决于你的具体漏洞情况。

就像代码中写的那样,我使用heaplib来分配字符串,这样更加的方便。

这种技术在Windows7上依然可以使用, 但是分配的次数要比在XP上更多一些。比如在XP上以500为堆喷的次数,0x0a042020作为起始地址。那么到了Windows7上则要进行900次喷射,并且以0x16402020作为起始地址。这样的结果是只要喷射的次数足够多的话,那么我们就能预测出堆分配的地址(而且这个地址可以我们来指定)。

下面来讲解一下简单的UAF漏洞如何进行利用。我发现的UAF漏洞通常都是这样子的:发生UAF的对象在不同行的js中被分配和释放,所以我们有充足的时间去我们指定的数据占位被释放的对象内存空间。

这是我们假设的存在UAF漏洞的代码:

var MyObject = new Object();//分配对象
var MyObjRef = MyObject.SomeProperty; //引用对象
MyObject.CleanUp(); //释放对象
alert(MyObjectRef.parent);//解引用对象

现在我们希望在对象被解引用之前,用我们控制的数据对释放的对象内存地址进行占位。在大多数的UAF漏洞中,发生UAF对象的虚函数都会发生调用。虚表指针就是一个对象的前四个字节的值,所以我们需要进行某种类型的堆喷射可以准确的填充到我们在对象虚表值覆盖的值的位置。

一个好消息是IE对刚刚释放的堆块进行了记录,如果我们申请一个大小大约相同的堆,那么那块内存就会被重新分配(我很怀疑真的是大约相同吗?)。这意味着,如果我们知道释放对象的内存大小,我们就可以用相同大小的我们自定义的数据去分配堆,而且结果会是相同的内存。

想知道对象的大小并不能,只需要对ntdll中的堆分配函数下断即可。我们必须再次分配正确的内存大小,一般我都是通过对div标签数组添加className属性来实现的这一点。这么做的优点是className属性是一个字符串,你可以对这个字符串指定任意大小。这个过程不会导致额外的堆分配(额外的堆分配可能会导致不能正确占位),并且字符串的内容是你自定义的,你可以指定第一个DWORD大小的数据为任意值。唯一的缺点是不能在字符串中使用\x00\x00,但是事实上占位根本用不到\x00\x00。

所以我们需要做一下几件事

  1. 创建数组来存放div元素( var DivArray = new Array(); )
  2. 用50个对象来填充这个数组
  3. 当UAF对象被释放掉后,执行js语句对内存进行占位
  4. 给divs标签添加classname属性( DivArray*i+.className = unescape(“%u4141%u4141......
  5. 解引用UAF对象

这样操作之后的结果会怎么样呢?

最可能的结果是这个样子的:

move eax, [ecx] ecx = our object memory.
call [eax+0x34] eax now holds 0x41414141

到目前为止,我们占位了UAF对象,控制了虚表指针。但是我们该怎么样绕过DEP保护呢?很简单,我们已经控制了eax寄存器。我们也清楚了占位堆的内存布局。我们首先要做的是把eax值指向堆喷的头地址。这样的话就会取堆喷处的0x34偏移的值来call了。但是由于有DEP保护,不能直接的在堆上执行代码。我们需要做的就是想办法调用VirtualProtect函数,把shellcode所处的内存的属性由可读可写设置为可读可写可执行。
举个例子,假设我们已经发现一些如下的指令序列(作为gadgets存在)

0x6ff02348 :

mov ecx,eax

call [eax+10]

and another that goes like:

0x6FF01234 :

push [eax+70]

push [eax+60]

push [eax+50]

push [eax+40]

push [eax+34]

push [eax+20]

call [ecx+14]

.....

.....

retn

那么,如果我们这么去设置堆喷的堆内容的话:(根据引用顺序排序)

  1. +0x34:0x6FF02348
  2. +0x10:0x6FF01234
  3. +0x14:0x7c801ad4 (VirtualProtect)
  4. +0x20:堆喷的首地址
  5. +0x30:0x200(单个堆喷块的大小)
  6. +0x40:0x40(READWRITEEXCUTE)
  7. +0x50:无意义的值,占位用

这样的话我们就成功的调用了VirtualProtect函数把内存的属性改成了可执行的。这种方法在XP上能够得到很好的执行,因为XP系统上我们可以准确的知道VirtualProtect的地址。在Windows7上利用我们需要更多的创造性。

我们在不知道kernel32.dll模块的准确基地址的情况下该如何调用VirtualProtect呢?IE的许多dll模块包含有ATL库,这些ATL库中会调用VirtualProtect函数。这意味着VirtualProtect函数处于我们已知的一个固定的偏移(相对dll基址)。假如我们知道dll加载的基地址是0x6fff0000,0x6fff1288是VirtualProtect函数的地址。我们需要做的就是在诸如call [eax+8]这样语句之前把eax设置为0x6fff1280。这可以通过想上面那样利用代码并设置堆喷的内容来实现。当我使用这种方法时,我经常把我的堆喷内容设置为连续增长的值,比如:

var pattern = unescape(“%u0000%u0001%u0002%u0003%u0004%u0005%u0006........”)

通过这种方法,就可以更容易的找出你的字符串中需要编辑的值。

本质上,我们要做的全部事情就是连接起已经准备好的这些代码块(gadgets)。但是只能使用call或是jmp去连接,直到成功的执行了VirtualProtect。然后我们的堆喷就具有了可执行权限。如果我们的执行流中向栈中压入的参数多于VirtualProtect函数需要的,那么返回堆栈将会被破坏,并且会结束掉我们的流程。

Peter Vreugdenhil

翻译 by:Ox9A82

【考古向翻译】Pwn2Own 2010 Windows 7 Internet Explorer 8 exploit的更多相关文章

  1. 关于windows 下每次打开IE 8都弹出欢迎使用Internet Explorer 8 弹窗的关闭方法

    今天笔者在安装完windows 操作系统后,发现了一个问题,即每次打开IE 8浏览器,都会弹出一个欢迎界面: 弹窗标题为:设置windows Internet Explorer,具体内容如下图所示: ...

  2. How to Uninstall Internet Explorer 11 for Windows 7

    Internet Explorer 11 is the newest version of Microsoft's web browser, but not everyone is a fan. If ...

  3. 企业IT管理员IE11升级指南【2】—— Internet Explorer 11 对Adobe Flash的支持

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  4. 如何使用BHO定制你的Internet Explorer浏览器

    原文出处:Browser Helper Objects: The Browser the Way You Want It一.简介 有时,你可能需要一个定制版本的浏览器.在这种情况下,你可以自由地把一些 ...

  5. 必应翻译:让Windows上的翻译不再是难事

    文章译自:Translations Made Easy on Windows 比方说今年夏天你想出国旅行,计划去一趟德国.你的行程很丰富:参观慕尼黑和柏林,乘坐游船沿莱茵河而下,再品尝几串摩泽尔的葡萄 ...

  6. IE中无法执行JS脚本 解决WINDOWS SERVER 2008弹出INTERNET EXPLORER增强安全配置正在阻止来自下列网站的内容

    在默认状态下,使用Windows Server 2008系统自带的IE浏览器访问网页内容时,我们时常发现“Internet Explorer增强安全配置正在阻止来自下列网站的内容”的提示导致不能打开网 ...

  7. 【翻译习作】 Windows Workflow Foundation程序开发-第一章05

    1.3      开发我们的第一个工作流 也许你曾经在这样的产品经理手下搞过开发:他总是在你身边转悠,并不时的问一句“你还没做完吗?”.在这一部分,我们将用一个简单的Windows Workflow程 ...

  8. 【翻译习作】 Windows Workflow Foundation程序开发-第一章04

    1.2.3  Windows Workflow运行时 从Windows Workflow的角度看,可以将工作流活动当成是交给一个工作流处理器去执行的一系列指令或操作码.在Windows Workflo ...

  9. 【翻译习作】 Windows Workflow Foundation程序开发-第一章03

    1.2.2.Visual Studio 2005扩展包 微软也为Windows Workflow开发者提供了Visual Studio 2005扩展包.扩展包将许多功能集成到Visual Studio ...

随机推荐

  1. [poj 1533]最长上升子序列nlogn树状数组

    题目链接:http://poj.org/problem?id=2533 其实这个题的数据范围n^2都可以过,只是为了练习一下nlogn的写法. 最长上升子序列的nlogn写法有两种,一种是变形的dp, ...

  2. iperf测试网络性能

      分类: LINUX 2013-06-17 18:52:21     Iperf是一个网络性能测试工具.可以测试TCP和UDP带宽质量,可以测量最大TCP带宽,具有多种参数和UDP特性,可以报告带宽 ...

  3. extract_by_one 根据二维数组中某字段来提取数组信息,查看有无重复信息

    public function tt(){ $param = array( array ( 'hykno' => '2222222-CB', 'tcdk_fid' => '458B6D70 ...

  4. unity还原three之旋转

    http://www.360doc.com/content/16/0829/14/12282510_586760119.shtml unity使用左手坐标系,另外在做旋转的时候必须弄清楚旋转坐标轴和旋 ...

  5. 我的编码习惯 - Controller规范

    原文出处: 晓风轻 请先阅读我这2篇文章 程序员你为什么这么累? 和 我的编码习惯 - 接口定义. 第一篇文章中,我贴了2段代码,第一个是原生态的,第2段是我指定了接口定义规范,使用AOP技术之后最终 ...

  6. java基础-System类常用方法介绍

    java基础-System类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.System类概念 在API中system类介绍的比较简单,我们给出定义,system中 ...

  7. day13 类的补充

    访问修饰符                          同包                          不同包 本类         子类         非子类        子类   ...

  8. 哈密顿图 哈密顿回路 哈密顿通路(Hamilton)

    本文链接:http://www.cnblogs.com/Ash-ly/p/5452580.html 概念: 哈密顿图:图G的一个回路,若它通过图的每一个节点一次,且仅一次,就是哈密顿回路.存在哈密顿回 ...

  9. angularJS $watch $apply $digest

    看O'Reilly的书看到$watch这部分,不过没看懂,网上很多资料也含糊不清,不过还是找到了几个好的,简单记录一下. 一句话说明,$watch是用来监视变量的,好了直接上代码 <html&g ...

  10. Java使用UDP发送数据到InfluxDB

    最近在做压测引擎相关的开发,需要将聚合数据发送到InfluxDB保存以便实时分析和控制QPS. 下面介绍对InfluxDB的使用. 什么是InfluxDB InfluxDB是一款用Go语言编写的开源分 ...