查看原文
其他

CVE-2014-6332学习笔记

输出全靠吼 看雪学院 2019-05-25

0x00 漏洞简介


CVE-2014-6332是微软2014年11月11日(数字很吉利)公布的一个IE浏览器漏洞(同时公布的还有CVE-2014-6352),影响IE版本为IE3-IE11。根据漏洞利用方法,官方定义为远程代码执行漏洞。


究其原因是因为vbs引擎在执行Redim array(nNum)时,即重定义数组时,会调用OLEAUT32.dll模块里面SafeArrayRedim函数,该函数内部处理逻辑不严谨,使用了错误的条件跳转指令,而且当传入的nNum足够大时,函数内部的数组空间申请会失败、SafeArrayRedim函数不做任何处理直接返回,导致返回时已经将nNum写入数组结构,后续对该数组便可以随意“越界”访问。



0x01漏洞分析


1.1讲点基础


1.1.1Vbscript中的VARIANT结构


VARIANT结构是脚本语言中常用的一种结构,用于封装对象结构。参见官方说明:


https://docs.microsoft.com/zh-cn/windows/desktop/api/oaidl/ns-oaidl-tagvariant


简化一下该结构,这是一个0x10大小的结构:

typedef struct _myVARIANT {                VARTYPE vt;//变量类型,占2字节                      WORD    wReserved1;                  WORD    wReserved2;                  WORD    wReserved3;//保留位,共6字节            DWORD   pHighData;//指向变量数据的指针。一般用于基本数据类型            DWORD   pLowData; //指向变量数据的指针。一般用于复合数据类型


VARTYPE结构参考:


https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/3kfz157h(v=vs.84)


列出常用的几种类型如下表所示:


接下来看一下Vbscript中的数组结构,参见:


https://docs.microsoft.com/zh-cn/windows/desktop/api/oaidl/ns-oaidl-tagsafearray


VARTYPE结构参考:


我们测试一下这些结构在内存中的存储情况。



在实际调试中发现,数组元素的类型是可以不一致的;使用redim重定义数组时,数组实际的元素个数为传入的nNum+1。



1.1.2 Vbs中将函数指针赋值给变量


Vbs中将函数指针赋值给变量时,先将函数类型的VARIANT结构压入求值栈,然后将求值栈中结构再传递给变量,但当检测到求值栈中的数据类型为0x400C(即函数类型)时,并不会传递此类型,引发相关异常。如果当前代码流设置了On Error Resume Next,则会忽略当前异常,执行下面的代码。



1.1.3 SafeMode


SafeMode是Windows操作系统中针对安全的一种特殊模式,即安全模式。在Vbs引擎中同样存在这样一个安全属性值,正常情况下该属性值为0xE。默认情况下Vbscript脚本执行权限是非常低的,正是因为safemode安全属性的限制,如若我们能通过一定方法修改掉此属性值(改为0),即可绕过安全权限检查,为所欲为,即进入上帝模式。而且,经过调试我们发现在COleScript对象偏移0x174位置正是Safe Mode标志。



所以我们对该漏洞利用的核心就是找到safemode标志的位置并修改它。


1.2漏洞分析


我们选用附件中一个弹计算器的Exp进行分析(stage2.html)。


分享一片帖子上的调试方法(博客链接见文末):由于Vbscript脚本由Vbs引擎解释执行,如果我们盲目跟踪解析流程非比较低效,我们调试的目的是为了复现漏洞位置的代码bug,所以定位到漏洞模块的解析位置是关键,跟踪关键数据的解析过程即可。


前面我们为了查看测试变量的内存结构手动加入了IsEmPty()函数的调用,在WinDbg中模糊搜索该函数,可找到其符号为Vbscript.dll!VbsIsEmpty,我们将想查看的对象作为参数传给VbsIsEmpty()函数,即可断在该函数进行对象结构的查看。此为为了方便我们判断脚本执行的流程,可以将自定义的日志信息字符串传给VbsIsEmpty()函数,然后下条件断点:

bp vbscript!VbsIsEmpty "r $t1=poi(@esp+c);r $t2=poi($t1)&0xF;


上述指令的意思是:下断VbsIsEmpty函数,如传入参数为字符串(即我们自定义的日志信息)则打印字符串,然后继续执行;否则就断下来(此时我们就可以查看特定的变量结构了)。



我们重点跟踪一下redim操作,在redim Preserve arrX(ofnumele)之前跟进redim流程。搜索vbscript.dll中redim相关符号,定位到一个可疑的函数Vbscript.dll!RedimPreserveArray,下断该函数并结合IDA进行动态跟踪验证,程序成功断下。我们发现在RedimPreserveArray内部会调用SafeArrayRedim函数,传入的两个参数(下图中为psa、&psaboundNew)分别为原数组对象指针和新的SAFEARRAYBOUND结构指针。


注意到SafeArrayRedim函数位于OLEAUT32.dll模块内。此后将通过SafeArrayRedim函数的返回值(注意图中的v4是一个有符号数)判断是否redim成功,若小于零则抛出异常结束RedimPreserveArray函数。



继续跟进OLEAUT32.dll中的SafeArrayRedim函数。


我们直接反编译SafeArrayRedim函数,该模块自带符号,简单分析一下该函数的伪代码,即可快速定位该函数中的逻辑bug(如下图所示),结合动态验证也正是如此。





总结一下该漏洞成因主要有两点:


A、SAFEARRAYBOUND结构中的cElements字段(即数组元素个数)是一个ULONG类型,即无符号长整形。但是在SafeArrayRedim函数里面处理新旧数组操作(此处说的处理是指上两图中对于变动的数组空间进行开辟新的缓冲区进行保存备份操作)时,条件跳转判断选择了jge有符号跳转指令(源代码中应该是定义错了数据类型)。


这样就存在一种可能:如果psaboundNew-> cElements  -  psa-> rgsabound.cElements>=0x08000000,即数组元素个数增加的值大于或等于0x08000000,其变动的大小就会大于等于0x80000000,该数值就会占用有符号数的符号位、使得图中的v5恒小于0,随后便会产生错误的跳转。


B、SafeArrayRedim函数里面的处理流程是先将psaboundNew结构赋给psa-> rgsabound,随后按照数组空间变动的大小去申请缓冲区,如果申请失败则会返回0x8007000退出,然后外层的Vbscript.dll!RedimPreserveArray函数将会抛出异常退出。这里的处理存在一个非常严重的问题:RedimPreserveArray函数redim失败之后却并未还原psa-> rgsabound.cElements。这让后续的psa数组“越界”合法化。


至此漏洞成因已分析完毕。



0x02 Exploit分析


接下来,我们分析一下附件中的漏洞利用文件stage2.html,学习一下该Exp的编写技巧及思路。前面的分析中提到该漏洞的常规利用方法是修改vbs引擎中的SafeMode标志开启上帝模式,而且我们知道COleScript对象偏移0x174位置正是Safe Mode标志。所以我们分析的重点是如何找到Safe Mode标志的具体位置并且合法的去修改该标志。


笔者在调试stage2.html时,简单总结了一下代码流程:


  1.   初始化数组arrX()、arrY()。(即Init()函数)。

  2.   通过循环redim尝试使得arrX和arrY空间“连续”(准确来讲使得原始数组arrX和arrY之间只间隔8字节)。(Exploit()函数)

  3.   触发漏洞修改arrX的cElements字段,使得arrX数组可“越界”访问arrY数组元素,让两个数组后续空间重叠。(Trigger()函数)

  4.   通过前面提到的将自定义函数指针赋给变量的方法获取获取CScriptEntryPoint对象地址、为获取Safe Mode标志位置做准备。(LeakFnAddr()函数)

  5.   获取COleScript对象地址,并通过数组重叠后的特性构造特定的数组空间布局以及伪造的数组结构myarray成功访问到Safe Mode并修改其属性值为0。此时已成 功开启上帝模式(EnableGodMode()函数)

  6. 执行自定义的shell。(runshell()函数)

详细调试注释见附件中的z.html文件。这里我们重点分析一下第4步和第5步。我们依然选用前面提到的通过打印日志快速定位关键代码的方法。





随后该函数arrX(olapPos)赋给LeakFnAddr返回,注意此时是将CScriptEntryPoint对象地址作为长整型赋给LeakFnAddr。


然后将调用ReadMenInt函数获取COleScript对象地址。前面我们已经知道poi(pCScriptEntryPoint+8)+0x10即可获取COleScript对象地址。


这里需要注意两个细节:


A、 通过arrY(0)=8间接地将arrX(olapPos)的类型修改为8(即v_str字符串类型)。


B、 Lenb函数的作用是获取字符串的字节总数,传入v_str类型参数该函数会按照v_str结构默认将字符串指针前四字节的DWORD值作为结果返回。这也是前 面执行arrX(olapPos)=addr+4的原因。



获取到COleScript对象地址之后,接下来要解决的问题便是如何合规的去修改COleScript+0x174位置的SafeMode标志了。


我们来分析一下这里的流程:


1、构造一个自定义的数据类型,即myarray。其数据内容为:

08800001 00000001 00000000 00000000 7fffffff  00000000


这里0x18字节的数据刚好是一个数组的结构(一个单元素字节长度为1,总共7fffffff个元素的一维数组,即byte array[0x7fffffff])。myarray是指向这个数组的自定义结构。


2、将myarray对象赋给arrX(olapPos+2)。此时arrX(olapPos+2)类型为0x4a,值为0x00676584、即myarray对象地址。


3、arrY(2)=8192+12。间接的修改arrX(olapPos+2)类型为0x200c,即vbArray|vbVariant类型(数组|变体类型)。


4、此时arrX(olapPos+2)已成功修改为数组类型,现在就可以正常的去访问该数组空间了,该数组空间从0x00000000到0x7ffffffe,即整个用户空间,SafeMode肯定位于整个空间。


5、前面已经获取ColeScript对象地址并传递给i保存,那么直接通过arrX(olapPos+2)(i+0x174)便可以访问SafeMode,将其修改为0。





至此,利用分析已完毕。


0x03 填个坑


笔者因为较少编写Vbscript文件,在分析该Exp时随手写了较多注释,然后调试就出现问题了……



上图红色方框(即Vbscript中关键字then之后的位置),若此处写注释则会连带下一行一起注释……



0x04 总结


该漏洞是一个存在于IE VBS引擎中的非常经典的数组“越界”的漏洞,对于研究IE漏洞是一个非常不错的选择。浏览器相关漏洞定位关键代码一直是重点也是难点,勤学苦练、重在积累。


非常感谢论坛上各位同仁分享的非常详细、高效的分析思路和方法。笔者分析功底有限,有任何分析不当或疏漏之处期望各位交流斧正。


参考链接:


https://blog.csdn.net/qq_32400847/article/details/77799191





- End -


看雪ID:输出全靠吼                              

https://bbs.pediy.com/user-808521.htm


本文由 输出全靠吼 原创

转载请注明来自看雪社区





热门技术文章推荐:



公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存