_ _
(_) | |
__ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_
\ \ / /\ \/ /| || | | || '_ ` _ \ | '_ \ | '_ \ / _ \| __|
\ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_
\_/ /_/\_\| | \__,_||_| |_| |_|| .__/(_)|_| |_| \___| \__|
_/ | | |
|__/ |_|
/---------------------------------------------------------------------------------------\
|>...................[ 漏洞CVE-2013-2551逆向分析 ]...................<|
|>......................[ by nEINEI/vxjump.net ]......................<|
|>......................[ 2013-12-24 ]......................<|
\>...................... [ neineit_at_gmail.com ] ......................
[目录]
[0x01] .简介
[0x02] .基本信息
[0x03] .漏洞分析
[0x04] .其它
[0x01] .简介
漏洞CVE-2013-2551是Vupen team在2013Pwn2Own拿下冠军比赛时利用的漏洞。
关于这个漏洞的分析已经有很多文章了,请参考:
http://zenhumany.blog.163.com/blog/static/171806633201403114815739/
http://blog.csdn.net/tony_whu/article/details/16368089
http://www.cnblogs.com/Danny-Wei/p/3766432.html
简单来说就是是VGX.DLL模块存在一个整数溢出漏洞,
我们着重讨论的是如何分析这个漏洞的产生原因。
[0x02] .基本信息
这个漏洞发生的模块是在VGX.DLL,且影响十分广泛包括:WINXP ~ WIN8 ,IE6~1E10
这里我们以Windows7 为例讨论这个问题,其它平台类似。
我调试时触发漏洞的一个版本:
Image path: C:\Program Files\Common Files\Microsoft Shared\VGX\vgx.dll
Image name: vgx.dll
Timestamp: Mon Jul 13 18:11:08 2009 (4A5BDB2C)
CheckSum: 000C2C1E
ImageSize: 000C1000
File version: 8.0.7600.16385
Product version: 8.0.7600.16385
File flags: 0 (Mask 3F)
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0409.04b0
CompanyName: Microsoft Corporation
ProductName: Windows® Internet Explorer
InternalName: VGX.DLL
OriginalFilename: VGX.DLL
ProductVersion: 8.00.7600.16385
FileVersion: 8.00.7600.16385 (win7_rtm.090713-1255)
FileDescription: Microsoft Vector Graphics Rendering(VML)
LegalCopyright: © Microsoft Corporation. All rights reserved.
漏洞利用的最后一个版本:8.0.7601.17984
补丁后的版本: 8.0.7601.18126
[0x02] .漏洞分析
先看一个PoC,运行这个页面代码将Crash,
/*
xmlns 全称就是XML NameSpace 也就是命名空间。Behavior(行为)也是IE5.0新推出的东西,它的功能非常强大,结合样式表,可以给任何HTML对象增加行为(新的属性、方法、
事件),而在这里,它的用处是把命名空间“v”和系统预定义的行为VML连接。这样定义以后,你就可以使用下面的标记了,和普通的HTML标记有所区
别,每个标记都增加了一个命名空间:
*/
// 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也给了细节不再赘述。