_ _ (_) | | __ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_ \ \ / /\ \/ /| || | | || '_ ` _ \ | '_ \ | '_ \ / _ \| __| \ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_ \_/ /_/\_\| | \__,_||_| |_| |_|| .__/(_)|_| |_| \___| \__| _/ | | | |__/ |_| /---------------------------------------------------------------------------------------\ |>...................[ 漏洞CVE-2013-2551逆向分析 ]...................<| |>......................[ by nEINEI/vxjump.net ]......................<| |>......................[ 2013-12-24 ]......................<| \>...................... [ neineit_at_gmail.com ] ...................... // IE=6 是标准模式, 如果IE=mutelateIE6 是兼容模式 程序会崩溃在VGX模块当中, 0:013> r eax=016fc000 ebx=19944964 ecx=41414141 edx=0832d0c8 esi=07da8ff0 edi=0832d144 eip=1993daba esp=0832d0dc ebp=0832d0f0 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 vgx!COALineDashStyleArray::put_item+0x87: 1993daba 8908 mov dword ptr [eax],ecx ds:0023:016fc000=???????? ecx是输入时构造的的41414141,eax是一个不可访问的内存地址 0:013> dd eax-20 l10 016fbfe0 00000000 00000000 0052e944 dcbabbbb 016fbff0 41414141 41414141 41414141 41414141 016fc000 ???????? ???????? ???????? ???????? 016fc010 ???????? ???????? ???????? ???????? 此时我们看看eax指向的内存可能是什么? 显然msvcrt!malloc+0x0000008d 和MsoFCreateArray是和这片内存关联的操作。 0:013> !heap -p-a eax address 016fc000 found in _DPH_HEAP_ROOT @ 16e1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 16e1d30: 16fbff0 10 - 16fb000 2000 11248e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 77f85e26 ntdll!RtlDebugAllocateHeap+0x00000030 77f4a376 ntdll!RtlpAllocateHeap+0x000000c4 77f15ae0 ntdll!RtlAllocateHeap+0x0000023a 6ff59d45 msvcrt!malloc+0x0000008d ***<---------------\ 198e56a5 vgx!GelHost::FAllocMemCore+0x0000000e | 1992c0cb vgx!MsoFInitPx+0x0000005e | 198ed223 vgx!MsoFCreateArray+0x00000044 ***<---------------/ 1995a13c vgx!VGPIE5array::FAddElement+0x0000001a 1995a1de vgx!VGPIE5DwordArray::Text+0x00000060 1992ceb7 vgx!GetArrayVal+0x00000086 1992d435 vgx!ParseDashStyle+0x00000021 19932cdc vgx!CVMLStroke::InternalLoad+0x00000100 19932849 vgx!CVMLShapeIOProxy::Load+0x00000022 198e3347 vgx!CSimpleTag::Load+0x000005df 198e42cd vgx!CPTPropBag2::Load+0x00000016 74e9e7c2 mshtml!CPeerHolder::InitAttributes+0x000000a9 74d77422 mshtml!CPeerHolder::AttachPeer+0x000000b8 下面需要看清楚源码中的几个关系: dashstyle="2 2" ; //看起来是给dashstyle这个属性赋值 tsl.dashstyle.array.length = -1; //给tsl.dashstyle.array长度赋值为-1. tsl.dashstyle.array.item(i)=0x41414141 // 毫无疑问,崩溃就是由于这个循环中写(赋值)操作造成的。 tsl.dashstyle.array.item项数 和 tsl.dashstyle.array.length 长度有没有关系呢? 手动都修给为10,不崩溃。 修改回tsl.dashstyle.array.length = -1,马上崩溃。 tsl.dashstyle.array.length = 10; for (var i = 0; i < 10; i++) { tsl.dashstyle.array.item(i)=0x41414141; } 好了,至此,我们已经可以大概的猜出来各种原因,tsl.dashstyle.array.length应该是可能表示有多少项的tsl.dashstyle.array.item, 当tsl.dashstyle.array.length=-1时,仅能写入4项,程序并没有分配出10项那么大的空间,也就是剩余6项没有分配。 目前,我们有1个线索就是和MsoFCreateArray是和这片内存关联的操作。 所以,下断点: bu vgx!MsoFCreateArray ,进入该时,我们发现分配内存的操作。 0:013> p eax=0837b354 ebx=0837b3bc ecx=0837b3bc edx=00000001 esi=0837b3c0 edi=00000101 eip=198ed1ee esp=0837b314 ebp=0837b324 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 vgx!MsoFCreateArray+0xf: 198ed1ee e88a67fdff call vgx!operator new (198c397d) 0:013> p eax=09af5fe8 ebx=0837b3bc ecx=00000014 edx=00000000 esi=0837b3c0 edi=00000101 eip=198ed1f3 esp=0837b314 ebp=0837b324 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 dd eax: 09af5fe8 c0c0c0c0 09af5fec c0c0c0c0 09af5ff0 c0c0c0c0 09af5ff4 c0c0c0c0 09af5ff8 c0c0c0c0 09af5ffc d0d0d0d0 09af6000 ???????? 09af6004 ???????? 09af6008 ???????? 执行完这句后 vgx!MsoFCreateArray+0x3f: 198ed21e e84aee0300 call vgx!MsoFInitPx (1992c06d) 内存变为: 09af5fe8 198d7258 vgx!ORG::`vftable' 09af5fec 00040000 ------------\这几处4的值引起我们的注意,大家可以修改一下源码的tsl.dashstyle.array.length 值 09af5ff0 00040004 ------------/都会在这里有直接反映。 09af5ff4 00000101 09af5ff8 09af7ff0 ------------> 这是一个新分配的内存,见下面 09af5ffc d0d0d0d0 09af6000 ???????? 09af6004 ???????? 0:013> dd 09af7ff0 09af7ff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 09af8000 ???????? ???????? ???????? ???????? 继续单步分析,主要是观察09af5fec,09af5ff0这些内存值的变化,我们注意到一个函数vgx!COALineDashStyleArray::put_length eax=0000000a ebx=19944964 ecx=1993dad5 edx=08437faa esi=017c3f90 edi=0837d194 eip=1993dad5 esp=0837d148 ebp=0837d160 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 vgx!COALineDashStyleArray::put_length: 1993dad5 8bff mov edi,edi 字面上猜测就是对DashStyleArray数组赋值的操作。那不就是tsl.dashstyle.array.length = -1 这样句吗? 继续调试,先看一些堆栈里面传入的参数是什么? 0:013> dd esp 0837d144 0837d160 6fc43e75 09d68ff0 ffffffff 所以arg1 = 09d68ff0 ,arg2= ffffffff . ffffffff 不就是-1吗,这里需要留意. 0:013> p eax=00000002 ebx=19944964 ecx=198d7258 edx=0837d118 esi=ffffffff edi=0837d194 eip=1993db46 esp=0837d12c ebp=0837d144 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 vgx!COALineDashStyleArray::put_length+0x71: 1993db46 3bc6 cmp eax,esi 0:013> p eax=00000002 ebx=19944964 ecx=198d7258 edx=0837d118 esi=ffffffff edi=0837d194 eip=1993db48 esp=0837d12c ebp=0837d144 iopl=0 nv up ei pl nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000217 vgx!COALineDashStyleArray::put_length+0x73: 1993db48 7d55 jge vgx!COALineDashStyleArray::put_length+0xca (1993db9f) [br=1] //jge 进行有符号比较,这样进入下一个分支,这个分支将影响内存的分配。 eax=00000003 ebx=19944964 ecx=09cb4fe8 edx=198d7258 esi=ffffffff edi=0832d17c eip=1993dba9 esp=0832d108 ebp=0832d12c iopl=0 nv up ei pl nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000217 vgx!COALineDashStyleArray::put_length+0xd4: 1993dba9 ff5228 call dword ptr [edx+28h] ds:0023:198d7280={vgx!ORG::DeleteRange (198ecf62)} 一直单步进入,直到, 0:013> p eax=00000002 ebx=00000003 ecx=07e12fec edx=00000002 esi=09af5fec edi=00000004 eip=1992c3c3 esp=0832d0c8 ebp=0832d0d4 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 vgx!MsoFRemovePx+0xa7: 1992c3c3 66291e sub word ptr [esi],bx ds:0023:09af5fec=0002 [esi] = 2 ,bx = 3 ; 相减是-1(0xffff),此时内存 09af5fe8 198d7258 vgx!ORG::`vftable' 09af5fec 0004ffff ------->这里已经被修改为4ffff 09af5ff0 00040004 09af5ff4 00000101 09af5ff8 09af7ff0 ------->这里只分配了4个项的内存 = 4 * 4byte,而目前已经被修改为存在4ffff项了。 09af5ffc d0d0d0d0 09af6000 ???????? 09af6004 ???????? 进而,tsl.dashstyle.array.item(i)=0x41414141; js语句不断触发下面的函数 eax=0000000a ebx=19944964 ecx=1993da33 edx=09184fe2 esi=07e1af90 edi=0832d144 eip=1993da33 esp=0832d0f4 ebp=0832d110 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 vgx!COALineDashStyleArray::put_item: 1993da33 8bff mov edi,edi 循环第5次时崩溃,因为09af7ff0没有分配那么大的空间。 至此,我们已经可以知道出问题的函数是vgx!COALineDashStyleArray::put_length 下面讨论一下,补丁对比的结果。 0.99 0.99 19929743 CVMLShape::Free(void) 1992969F ?Free@CVMLShape@@UAEXXZ 0.98 0.99 1994CFEC CVMLViewportView::FreeView(void) 1994CF69 ?FreeView@CVMLViewportView@@MAEXXZ 0.98 0.99 1994BEDF CVMLShapeView::FreeView(void) 1994BE7A ?FreeView@CVMLShapeView@@MAEXXZ 0.97 0.99 19950308 CVMLShapeView::InvalidateView(IVMLUpdateInfo *,MSOTPX *) 19950215 ?InvalidateView@CVMLShapeView@@UAEXPAVIVMLUpdateInfo@@PAV?$MSOTPX@PAVIVMLView@@@@@Z 0.88 0.98 198ED0A1 ORG::FAppendRange(void const *,int) 198ED031 ?FAppendRange@ORG@@UAGHPBXH@Z 0.85 0.93 199538A7 CVMLShape::FSavePathV(ushort * &,bool) 19953728 ?FSavePathV@CVMLShape@@QAE_NAAPAG_N@Z 0.85 0.99 1993DB35 COALineDashStyleArray::put_length(int) 1993DB17 ?put_length@COALineDashStyleArray@@UAGJH@Z 0.73 0.96 199536C1 SavePathSeg(ushort *,uint,ushort const *,uint,tagPOINT *,uint &) 199535B5 ?SavePathSeg@@YGIPAGIPBGIPAUtagPOINT@@@Z 0.46 0.84 1994F4AE CVMLViewportBgView::~CVMLViewportBgView(void) 1994D986 ??1CVMLViewportBgView@@UAE@XZ 0.35 0.73 1994E8D8 CVMLShapeView::~CVMLShapeView(void) 199264F8 ??1CVMLShapeView@@UAE@XZ 显然存在COALineDashStyleArray::put_length(int)这个函数被修补了, 增加了3处代码 (1) .text:1993DB6C mov edi, [ebp+arg_4] // 这里是参数ffffffff .text:1993DB6F test edi, edi .text:1993DB71 jl loc_1993DC29 // 有符号比较,条件成立直接跳向函数结束位置 (2) .text:1993DBB2 mov esi, edi .text:1993DBB4 sub esi, eax .text:1993DBB6 cmp edi, 3FFFFFFFh //大于3fffffff,跳走到结尾 .text:1993DBBC ja short loc_1993DC20 (3) .text:1993DC20 mov [ebp+var_10], 80004005h .text:1993DC27 jmp short loc_1993DC30 对于补丁后的函数,直接在(1)的地方跳走了,也就是说-1这样的赋值给tsl.dashstyle.array.length的操作不会改写内存结构。 不存在再次越界访问的可能。 [0x04] .其它 CVE-2013-2551是个高质量的漏洞,整数溢出后通过堆fengshui布局可以进行信息泄露,或是代码流程控制,当然最关键是要看越界后 写入哪些对象的字段来获得控制权,相关的利用Vupen Team也给了细节不再赘述。