发布时间:2014-04-28 12:39:46作者:知识屋
最近有个 IE 0day (CVE-2014-0322)被用于挂马。尽管这个本身存在于 IE 里面,但是为了 实现成功利用,这个样本还借用了 flash 作为辅助,来突破各种防护。IE+flash 的组合也给分 析带来了一些挑战,以前没有分析过这样的组合,正好借此机会详细分析了一下,整理成文 章,大家一起交流学习。如有错误之处,还请大家批评指正。
本文涉及的内容包括:
1. 整个 exploit 的流程分析。
2. 漏洞的成因。
3. 使用 flash uint vector 进行 DEP/ASLR 绕过的技术。
4. 样本中的 ROP 片段。
5. 样本的 shellcode 行为。
本文使用的样本一共包含三个文件
Index.html (就是那个 html 文件,原名叫什么我忘了) Tope.swf
Erido.jpg
这些文件在网上搜一下基本都能找到了,我这里就不给出来了。
整个攻击的入口点是 index.html,它会尝试去加载 Tope.swf:
1 <embedsrc=Tope.swfwidth=10height=10></embed>在 Tope.swf 初始化的时候,它首先尝试从服务器获取”Erido.jpg”
1 2 3 4 _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),因此每个对象实际占用的内存大 小是 0×1000 字节(0x3fe * 4 + 8)。这部分 spray 总共需要大约 400M 左右的内存。
1 this.s =newVector.同时 Tope.swf 还会 spray 少量的 flash object vector,里面存放了同一个 flash.media.Sound 对 象的引用:
1 2 3 4 5 6 7 8 while(_local2 < 0x0400) { this.ss[_local2] =newVector.<Object>(_local9); _local3 = 0; while(_local3 < _local9) { this.ss[_local2][_local3] =this.snd; _local3++; }; _local2++; };
做完 heap spray 后,flash 里面会通过 ExternalInterface 调用 index.html 里面的“puIHa3”函数。
“puIHa3” 函数会尝试触发 CVE-2014-0322 漏洞,这是一个 CMarkup 对象的 user-after-free 漏
洞。网上已经有很多关于漏洞原理的分析了,这里就简单过一下:
当调用 appendChild 时,MSHTML!CElement::Var_appendChild 被调用,在这个过程中一个新
的 CMarkup 对象会被创建:
然后 appendChild 继续运行,来到这里:
1 2 MSHTML!CMarkup::NotifyElementEnterTree+0x1df call CElement::HandleTextChange(bool)这个函数的调用最终会触发 onpropertychange 事件,于是我们之前注册的回调函数会被调用, 回调函数中的一行代码回引发 DOM 的释放,从而造成 CMarkup 对象的释放:
1 this.outerHTML=this.outerHTML// frees the DOM thus frees the CMarkup Object在 CMarkup 对象被释放以后,样本立即尝试将释放的内存站位:
1 2 3 for(a=0;a<arrLen;++a) { g_arr[a].title=d.substring(0,d.length); }
上述代码通过分配一系列 string 对象,来实现站位。
在 CMarkup 被释放并被占位以后,程序继续运行,来到这里:
这里 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 处的内存数据是不是这样:
1 2 3 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]指令之后,内存为:
1 2 3 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 中继续执行。
回到 flash 以后,首先样本会尝试找到那个大小被修改的 vector,我们叫它”V1”。然后执行
如下语句:
V1[0x3fe] = 1073741808;
很明显,这里下标已经越界了(因为定义 V1 的时候其长度为 0x3fe)。于是造成的效果时越 界写入了一个 dword。由于 spray 时这些 vector 是连续分配的,这个 1073741808 实际上覆 盖到了 V1 下面一个 vector 的长度字段,我们把这个 vector 叫做”V2”。
因为 V1 在内存中地址为 0x1a1b2000 , 因此 V2 的起始地址为 0x1a1b3000 (每个 vector 占 0×1000 字节),我们看一下 V2 的内存数据
可以看到,V2 的长度字段已经被篡改成了一个非常大的值 0x3ffffff0 (1073741808)。此时通 过操作 V2,我们几乎可以对整个内存空间实现任意读写。至此,“任意地址加一”成功转化 成了“任意地址读写”。
下面为了过 DEP 保护,样本开始构造 ROP。利用任意地址读写的功能,它在进程的内存空 间里面搜索 ROP 指令和函数,用的是 ntdll 里面的指令做 ROP。,这里讲一下搜索的基本过程, 详细的大家可以自己看代码。
flash.media.Sound 对象指针 -> flash.media.Sound 对象虚函数表 -> flash 模块基 地址 -> flash 某块导入表 -> kernel32 函数地址 -> kernel32 基地址 -> kernel32 导入表 -> ntdll 函数地址 -> ntdll 基地址 -> (ZwProtectVirtualMemory 地址和 [xchgeax,esp;ret;] 指令地址)
接着样本覆盖某个 flash.media.Sound 对象的虚函数表, 然后调用其函数,让控制流跳转的 ROP:
Flash!IAEModule_AEModule_PutKernel+0×212712:
66769ae2 ff5070 call dword ptr [eax+70h]
ds:0023:1a1b3170=77a646a8
这次的 ROP 相当简单,只有两步:
第一步:
第二步:
1 ntdll!ZwProtectVirtualMemory (1a1b3000, 1000, PAGE_EXECUTE_READWRITE)第一条 ROP 指令将栈指针指向可控的内存,第二条指令将第二阶段 shellcode 的属性改为可 执行,然后返回到第二阶段的 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 != 0×95: b ^= 0×95
2. 扔两个 PE 下来: %TEMP%sqlrenew.txt %TEMP%stream.exe
3. 调用 LoadLibrary 加载 sqlrenew.txt
4. 返回到 flash 代码
这次的样本,虽然漏洞出在 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.
2011-06-17
电脑开机时出现lass.exe进程是病毒吗?
自拍须谨慎!教你如何通过照片定位查看拍摄地点
电脑病毒最基础知识
黑客学员必须了解的C语言技术
精典详细内网渗透专题文章
教你破解Tp-Link的无线路由密码
解决SecureCRT中文显示乱码
QQ电脑管家和360哪个好?横评实测对比
攻防实战:无线网络路由入侵过程