永利欢喜娱人城·(中国区)官方网站

永利欢喜娱人城
  • 数字经济的清静基石

    首页 > 关于我们 > 永利欢喜娱人城动态 > 2019 > 正文

    一个补丁引发的RCE: 对CVE-2019-1208的深入剖析

    阅读量:

    前言

    CVE-2019-1208是趋势科技的@elli0tn0phacker在今年6月发现的一个vbscript误差,陈诉中提到这个误差是通过补丁比对发现的,这引起了笔者的兴趣。最近,笔者花了一些时间对该误差举行了较量详细的研究。在这篇文章中,笔者将从误差成因、修复方案、使用编写三个方面临该误差举行先容。

    读者将会看到,代码开发者是怎样在修复旧误差时不经意间引入新误差。在这个例子中,引入的照旧一个很是严重的远程代码执行误差。通过这个例子读者也会发现,有时间通过补丁比对就可以发现新误差。

    该误差从2019年6月更新被引入,到2019年9月更新被修复,只存活了短短3个月,因此编写这个误差的使用并无价值,笔者写这个误差的使用只是为了看法验证。

    只管微软已经在2019年8月的IE更新中周全禁用了vbscript,但出于清静性思量,完整使用代码不予果真。

    ?

    误差成因

    这是一个vbscript的UAF(Use After Free)误差,误差成因还要从微软今年6月的补丁提及。

    误差成因

    微软在2019年6月的vbscript更新中引入了下面几个函数:

    ?SafeArrayAddRef

    ?SafeArrayReleaseData

    ?SafeArrayReleaseDescriptor

    ?

    引入SafeArrayAddRef的作用是为SafeArray提供一种类似引用计数的机制。

    ?

    源码中通过使用STL的 map将一些工具/数据指针(如pSafeArray和pvData)与一个int型的计数器举行绑定。

    ?

    在VbsFilter和VbsJoin这两个函数中,在挪用现实的rtJoin和rtFilter前,会挪用SafeArrayAddRef对相关指针的引用计数+1。挪用完毕后,再挪用SafeArrayReleaseData和SafeArrayReleaseDescriptor在map中将指针对应的计数-1,并将指针所对应的key从map中删除。

    ?

    开发者应该是用这种方式修复了一些UAF问题。但修复方案中没有思量到当Join/Filter传入的数组中有类工具时,在Public Default Property Get这一潜在的回调中可以对数组举行操作(好比ReDim)。这样,当挪用完 rtJoin/rtFilter后返回VbsJoin/VbsFilter时,对应的pSafeArray/pvData指针已被更新,原先的设计是将之前已在Map中“注册”的指针传入后续的SafeArrayReleaseData/SafeArrayReleaseDescriptor举行引用计数减操作,但现在传入SafeArrayReleaseData/SafeArrayReleaseDescriptor的指针均不在map中(由于被重新建设了)。这导致在挪用RefCountMap::Decrement函数时,find要领找不到对应的key,函数直接返回0。这个返回效果被SafeArrayReleaseData/SafeArrayReleaseDescriptor明确为对应的指针的引用计数为0,从而将对应的SafeArray工具和数据销毁。

    ?

    详细地,开发者借助RefCountMap类实现了一个“伪引用计数机制”,通过一个map将所体贴的SafeArray指针与一个int型计数器绑定起来,计数值只有0、1、不存在,三种情形。

    ?

    相关操作函数的声明如下:

    RefCountMap::Decrement函数的伪代码如下:

    相识了这些知识后,回过头去明确@elli0tn0phacker陈诉中的Figure 5就会容易多了。

    ?

    PoC剖析

    @elli0tn0phacker给出的poc大致如下:

    由于误差的存在,我们知道arr(0) = 1语句执行前arr已被释放,而且从代码中可以看到arr是在回调中被ReDim的。那么arr到底存在那里?为什么arr(0) = 1索引的是ReDim后被释放的SafeArray,而不是Redim前的SafeArray?

    这就涉及到 vbscript虚拟机的相关知识。

    卡巴斯基实验室的Boris Larin曾写过一篇关于vbscript虚拟机的文章,而且开源了相关的调试插件。

    在文章中,作者对vbscript虚拟机举行了较量详尽的先容。vbscript的所有代码都市先被编译为P-Code,随后通过CScriptRuntime::RunNoEH对所有P-Code举行诠释执行,CScriptRuntime工具的成员变量中存储着诠释所需的许多信息,较量主要的几个如下:

    借助调试插件,我们可以获得 PoC代码编译后的P-Code:

    ?以下是上述用到的部门指令对应的字节码(所有指令请参考Boris的插件源码):?

    从P-Code中可以看出, arr(0) = 1这句对应的指令索引的是当地变量栈(OP_CallLclSt, 0x25),Call Join(arr)这句对应的指令索引的也是当地变量栈(OP_LocalAdr, 0x19),从两个指令名称中我们可以推测arr被存储在当地变量栈上。?

    ?

    在IDA Pro中对vbscript!CScriptRuntime::RunNoEH举行逆向,我们来看一下上述两个指令诠释分支的汇编代码:?

    上述两个分支都挪用了CScriptRuntime::PvarLocal要领,再来看一下CScriptRuntime::PvarLocal要领的实现:

    可以看到CScriptRuntime::PvarLocal吸收一个索引,而且基于CScriptRuntime工具+0x28或0x2C处的值举行偏移运算。调试时发现PoC两处对arr的操作索引均为1,以是存储arr的地址为:

    poi(pCScriptRuntime + 0x28) - 0x10*1? ?

    上述剖析验证了上面临于指令作用的意料,PoC中每次使用arr变量时,都市传入对应的索引去当地变量栈中举行会见。

    ?

    明确了arr的存取原理后,我们可以清晰地在调试器中视察arr的转变历程,从而明确整个UAF的历程。

    ?

    笔者在开启页堆后对PoC举行了调试。我们先将断点下到OP_LocalAdr指令的诠释分支,可以看到Join(arr)执行时会见到的arr,掷中止点时ebx即为CScriptRuntime,调试时arr从当地变量栈(ebx+0x28)举行索引,读者请注重下图中蓝色高亮的指针,ReDim语句执行后它会发生转变。

    我们对上图中高亮数据(SafeArray指针)所在的内存下一个写入断点,视察这个位置上数据的一再转变历程。

    ?

    第一次是在ReDim(OP_ArrNamReDim)执行时,对之前arr的整理阶段(OP_ArrNamReDim指令的诠释流程在后面“修复方案”一节中会进一步说明。):

    第二次是在OP_ArrNamReDim执行时,将新建设的arr复制到当地变量栈的对应内存处,可以看到蓝色高亮处的指针已经发生转变,此时的SafeArray已经变为刚刚建设的二维数组。

    最后,我们将断点下到OP_CallLclSt的诠释分支,目的是断在arr(0) = 1这句对arr的会见历程,由于“误差成因”所形貌的设计上的问题,此时当地变量栈上的arr已经被释放:

    追踪到的释放栈回溯如下图,读者可以看到,这个不妥的释放正是由于SafeArrayReleaseDescriptor传入了未在map注册的指针所导致。

    通过以上调试,读者应该可以清晰感受到整个Use After Free历程。

    ?

    修复方案

    清晰误差成因后,我们来看一下微软在9月更新中是怎样修复该误差的。笔者用Bidiff工具比对了8月更新和9月更新两个vbscript.dll,发现在rtJoin(rtFilter均类似,下面只以rtJoin举行说明)函数中,在对数组内的元素举行操作前后,加了一对SafeArrayLock/SafeArrayUnlock函数:?

    微软接纳对SafeArray加锁的方式来修补这个由之前的补丁引入的问题。SafeArrayLock会令pSafeArr->cLocks的值+1。这样,当在安装9月补丁后再次打开PoC。由于前面的+1操作,就可以令ReDim指令无法获得正常执行,我们来看一下详细的逻辑。

    ?

    这里再引述一下上面提到的P-Code,可以看到ReDim arr(1, 1)这句语句对应的P-Code如下:?

    笔者在调试器中跟了一遍OP_ArrNamReDim指令(0x0A) 的执行逻辑,发现有如下几个要害点:

    有意思的是,调试前笔者以为这里的ReDim最终会挪用oleaut32!SafeArrayRedim函数,效果并没有。

    ?

    团结上述逻辑,当补丁中在操作Join传入的数组前,SafeArrayLock令pSafeArr->cLocks从0变为1,从而在执行ReDim arr(1, 1)对应的指令时,无法通过3.1.1这一步,新数组无法被建设,Join函数执行完后当地变量栈中的数组指针不会获得更新,之前的UAF问题也就无从谈起了。Filter函数的修复方案同上。

    ?

    以下为上述历程中涉及到的函数挪用及说明:

    这个修复方案和CVE-2016-0189的修复方案思绪一致。

    ?

    使用编写

    @elli0tn0phacker在他的陈诉中已经给出了这个误差的exploit编写思绪,但没有宣布完整代码。作为看法验证,笔者亲手编写了对应的exploit,以下对部门细节举行说明。

    ?

    伪造超长数组

    通过触发误差,可以获得一块巨细为0x30的空闲内存。借助堆的特征,若是在Join函数执行完后连忙申请一些字符串长度为(0x30 - 4)的BSTR工具,就可以实现对被释放内存的占位。减4是由于BSTR的字符串前面尚有4字节的长度域,会一并申请。

    实践证实这里的操作照旧较量简朴的,并不需要过多的堆风水技巧,下面是一个可以乐成占位的代码示例:

    占位后,由于笔者已经在字符串中结构了假的超长数组,当下次会见arr时,乐成占位的字符串会被诠释为SafeArray结构体,从而获得一个基地址为0,元素个数为0x7fffffff,元素巨细为1的超长数组。

    ?

    恣意地址读取

    这部门,以及怎样结构一块可读写内存的步骤请参考@elli0tn0phacker的陈诉,相关步骤实现起来很是简朴,这里不再重复叙述。

    ?

    Bypass ASLR

    在前面的基础上,就可以泄露一个指针工具以绕过ASLR,这里笔者接纳的要领和和CVE-2019-0752一样,泄露一个Scripting.Dictionary工具的虚表指针,详细操作如下:

    ?

    虚函数挟制

    若PoC要在windows 10上执行,必须要绕过CFG。笔者最终接纳了@elli0tn0phacker在他陈诉中提到的要领,即对CVE-2019-0752的使用方式稍作改动:

    1.借助BSTR复制并伪造一个假的Dictionary虚表(fake_vtable),并改写Dictionary.Exists函数指针为kernel32!WinExec,由于kernel32!WinExec是系统自带函数,因此可以绕过CFG检测

    2.借助BSTR复制并伪造一个假的Dictionary工具(fake_dict),将虚表替换为上述的假虚表,将WinExec的下令行参数写入虚表指针后4字节最先的地址

    3.将假的Dictionary工具所对应BSTR的type设为0x09,使之成为一个工具(VT_DISPATCH)

    4.挪用fake_dict.Exists,使控制流导向WinExec函数,下令行参数在步骤2中已经结构好

    ?

    这个历程的示例代码如下:

    使用约束

    这个误差使用在恣意地址写上有一些受限条件,@elli0tn0phacker已在他的陈诉中提到,这里也不再重复叙述。

    ?

    这里提一个笔者编写使用时遇到的问题,笔者一最先是在windows7 sp1 x86情形下写的使用,代码所有写完后发现盘算器无法弹出,一番调试后发现,传入WinExec函数的下令行参数无法获得正常诠释,缘故原由也很简朴,来看一下某次win7调试时最终传给WinExec的参数:

    出于使用结构的约束条件,下令行参数的前4个字符是由前面伪造的虚表的地址诠释而来,这种情形下很容易造成前4个字符内里有多余字符,因此WinExec也就不能按预期执行后续的下令行。笔者一最先想到的将虚表伪造到0x20202020这个地址,这样下令行参数的前4个字符可以被诠释为空格,不会影响整个下令行的诠释。但该误差中对指定地址的一连写是受限的,笔者最终放弃了这个思绪。

    ?

    厥后笔者将未加修改的exploit在win10情形试了一下,发现盘算器可以乐成弹出,以下为某次在win10下调试获得的参数及伪造的虚函数表:

    笔者推测win10和win7下历程建设相关函数对下令行参数的处置赏罚存在一些差异,win10上的容错性更高一点。

    ?

    代码执行

    最终,笔者乐成在windows 10 1709 x86系统的2019年8月全补丁情形上弹出一个盘算器:

    ?

    参考资料

    《Delving deep into VBScript》

    《From BinDiff to Zero-Day: A Proof of Concept Exploiting CVE-2019-1208 in Internet Explorer》

    《RCE WITHOUT NATIVE CODE: EXPLOITATION OF A WRITE-WHAT-WHERE IN INTERNET EXPLORER》

    关闭

    客服在线咨询入口,期待与您交流

    线上咨询
    联系我们

    咨询电话:400-6059-110

    产物试用

    马上预约免费试用,我们将在24小时内联系您

    微信咨询
    永利欢喜娱人城信息联系方式
    1. 【网站地图】【sitemap】
      友情链接:凯发K8天生赢家一触即发  乐天堂fun88  yd2333云顶电子游戏  安鑫娱乐  j9九游真人游戏平台  美高梅官网  j9集团首页  4008云顶集团  j9九游会国际  优发国际随优而动一触即发  欧博abg  大发welcome登录  ayx爱游戏  彩乐园  拉斯维加斯游戏  合乐888  申博太阳城  Welcome购彩国际  新利体育·luck18  优发国际随优而动一触即发  万象城AWC  J9直营集团  pp电子  AG8大厅登录