office CVE-2017-11826杂谈
该漏洞为office中的一处混淆漏洞,相应的poc如下所示:可以看到其中font标签未闭合。
该漏洞中一个重要的点在于明白对应poc中解析标签在内存中的结构,如下所示为其中漏洞触发时的地方,这里有两个重要的函数即fun_GettagObject,fun_CalcspectailTagobject,
fun_GettagObject:返回当前tag对象,传入的参数为一个taglist对象,实际索引依赖于fun_CalcspectailTagobject
fun_CalcspectailTagobject:通过传入的level层级返回数组中对应的tag对象,如下所示漏洞触发时使用的正是fun_CalcspectailTagobject返回的Tagobject对象,在poc下该对象被混淆为一个font对象,从而导致后续调用对象虚表函数时的代码执行。
具体的Taglist/TagObject结构如下所示(这个地方感谢部门魔法师同学的提醒):
如下所示为对应的fun_GettagObject函数,该函数的参数为一个Taglist,首先获取对应的current_index,之后通过fun_CalcspectailTagobject获取当前curren_index标记的Tagobject
fun_CalcspectailTagobject,首先比较索引层级和当前层级,之后获取对应TagObect数组中对应的tag对象,公式为taglist base address + head len + index * tagobject len
如下图所示为正常对应的Taglist在内存中的布局,头部长度为0x10,偏移0x0的位置为current_index,之后为对应TagObject arragy,如下所示
将下图对应到poc中,可以看到此时对应的标签,由于对象存在数组中,所以实际标签层级要比数组中大一,这也就是索引时减一的原因。
下图为漏洞函数的父函数,在处理对应的poc时,font标签会在fun_copy5_Vul_17_11826中生成并完成对应对象的初始化,然后返回,而对于其余的标签,如oleobject则在第二个红框fun_may_TagobjInit中完成初始化,注意初始化时会将taglist中的curren_index+1,如oleobject对象进入漏洞父函数是current_index为3,在fun_may_TagobjInit中完成初始化后变成4(即实际的level,对照上图),font进入漏洞函数父函数时current_index为4,fun_copy5_Vul_17_11826执行之后为5。
当一个标签解析完后,会调用以下函数对current_index减一,如正常闭合font标签的doc中在解析完font后会将current_index减一,之后再进入到idmap的解析流程中,而office中这个减一的过程应该是依赖于结束标签,至少font标签如果没有对应的结束标签则不会对curren_index减一,这也是导致该漏洞的根本原因(即无闭合标签,导致fun_may_sub函数未调用,Taglist中的current_index未减一,后续标签寻址的时出错)。
通过以下断点对比正常doc和漏洞poc标签处理的过程,可以首先下第一个断点,断下之后g两次,然后再下后续的断点,这样可以减少大量不必要的断下。
bp wwlib+0x000861d4 ".printf \"vul_fun\";du poi(poi(esp + 8) + 18) Lpoi(poi(esp + 8) + 1c);dc poi(poi(poi(esp + 4) + b14)) L8"
bp wwlib+0x0003d3fb ".printf \"parent_fun\";du poi(poi(esp + 8) + 18) Lpoi(poi(esp + 8) + 1c);dc poi(poi(poi(poi(esp+4)+b10) + b14)) L8"
bp wwlib+0x0003d5e9 ".printf \"font copy and level+1\\n\""
bp wwlib+0x0004e3a8 ".printf\"tag level+1\\n\""
bp wwlib+0x00033aad ".printf\"font level-1\\n\""
如下图所示可以看到左右两边分别是从处理oleobject开始到漏洞触发函数正常和不正常的文档的标签输出(左为正常doc,右为poc),其中最大的区别就在于正常情况下font会对current_index中减一,最终到处理idmap时进入漏洞父函数时为4,之后+1=5,最后传入漏洞函数时为5,而poc中传入漏洞函数时为6。
回到触发漏洞时的代码,此时如果是正常情况,进入idmap是current_index为5,函数fun_CalcspectialTagobject中索引的位置为5-2=3,即Tagobject array[3]的对象,为oleobject对象,但是当运行poc时,current_index为6,6-2=4,即Tagobject array[4]的对象,为font对象,即正常情况上用于处理oleobject对象的代码,被用于处理font对象,由于这两个对象在内存中是完全不同的内存布局从而导致代码执行。
下图为触发时通过fun_CalcspectialTagobject返回的Tagobj对象,可以看到该对象就是font对象
下图为漏洞触发时对应的Taglist,可以看到正常应该调用时获取的应该是Tagobject[3]的oleobj对象,由于漏洞导致current_index未减一,通过6-2=4获取的却是之后Tagobject[4]中的font对象,反应到之后具体的比特位就是正常应该返回03a07780,却返回了05696b00
可以看05696b00+44的位置就是poc中攻击者可控的heap sprey地址,从而导致之后call [ecx+4]时代码执行,而正常的03a07780+44位置是一处虚表,从而在call [ecx+4]中调用的时正常的函数处理流程。
相关参考:
https://www.anquanke.com/post/id/87122
https://bbs.pediy.com/thread-221995.htm
感谢魔法师的提醒-_-
转载请注明出处