暴雷漏洞(CVE-2012-1889)分析报告

暴雷漏洞(CVE-2012-1889)分析报告
[toc]
1.软件介绍2.漏洞成因3.利用过程XP+IE6堆喷射(Heap Spray)分块堆喷WIN xp+IE8下漏洞利用DEP绕过DEPReturn to lib精准堆喷Ret2Libc链的构造与绕过DEP死循环问题WIN7+IE8漏洞利用绕过ASLR的方法:4.附件POCwinXP+IE6.0winXP+IE85.总结6.参考资料

暴雷漏洞(CVE-2012-1889)分析报告

软件名称:Microsoft Internet Explorer 6.0/8.0 操作系统:Windows XP/2003/7/8
组件版本XML 3.0/4.0/5.0/6.0 漏洞编号CVE-2012-1889
漏洞模块msxml3.dll 危害等级高危
模块版本8.90.1101.0 漏洞类型缓冲区溢出
编译日期2008-04-14 威胁类型:远程

1.软件介绍

Microsoft XML CoreServices(MSXML)是一组用于用Jscript、VBScript、Microsoft开发工具编写构筑基于XML的Windows-native应用的服务。

2.漏洞成因

Microsoft XML CoreServices 3.0~6.0版本中存在漏洞,该漏洞源于访问未初始化内存的位置。远程攻击者可借助特制的web站点利用该漏洞执行任意代码或导致拒绝服务。

该漏洞产生于msxml3.dll模块中,msxml3.dll是微软的一个SAX2 帮助程序类。主要用途包括:XSL 转换 (XSLT) 和 XML 路径语言 (XPath) 的完全实现、对 XML (SAX2) 实现的简单 API 的修改,包括与万维网联合会 (W3C) 标准和 OASIS 测试套件保持更高一致性。

3.利用过程

根据网上的资料,大致可以了解到漏洞利用过程由易到难有3个层次:

操作系统和IE版本 数据执行保护(DEP) 随机基址(ASLR)
XP + IE6
XP + IE8 开启
Win7 + IE8 开启 开启

因此我们从简单开始逐层提高利用,并且详细分析漏洞成因。

XP+IE6

  • 网上搜集到的poc,可验证漏洞存在:
image-20200115111326475.png

使用如上的poc通过windbg附加调试,程序运行崩溃中断处如下图:

(报错处:程序中断,我们能够看到从eax+18h(0x5f5ec6a3)取内容并作为函数地址执行,但是地址内容不可读造成程序崩溃。通过回溯能够看到ecx来自于eax内容来自于ebp-14h,由此推断内容不可读是栈内数据出错导致)

image.png
  • 使用OD详细看内存

通过内存我们能够看到ECX+18当中已经不是一个可访问的地址,所以在call时直接报错。

image.png
  • 搜集到poc2继续测试,poc2验证:
image.png

poc中javascript代码在代码1处会构造超长的字符串,代码2处将字符串设置为图片访问路径,最后调用definition方法定义当前文本对象obj15PB。
通过windbg调试看到程序崩溃处,在读取寄存器eax的值时导致程序崩溃,并且地址为0c0c0c0c


image.png

通过OD调试能够看到,eax内容是0c0c0c0c


image.png
  • 通过以上两个POC我们能够看到,poc1可以让程序崩溃,poc2能够将eax填充为0c,那么我们通过poc2的方式将eax填充为我们想要的内容就能利用该漏洞。

  • poc2将作为图片路径的字符串填充成超长数据0c,并且造成溢出,导致eax栈中数据为0c,导致最终函数调用地址编程0c0c0c0c,那么在利用漏洞时将0c0c0c0c地址内容覆盖为shellcode即可达到漏洞利用的目的。

堆喷射(Heap Spray)

为了在浏览器攻击中获得可预测的shellcode地址,堆喷射(Heap Spray)技术被发明出来,Heap Spray技术在Exploit中的利用开始于2001年,针对浏览器的堆喷射一般通过JavaScript执行,通过JavaScript申请大段的堆内存,再通过漏洞控制EIP,跳到堆中可预测的地址处执行shellcode。

  • 应用内存原理

    从windows95开始,windows操作系统就开始构建在平坦内存模型上面,该模型在32位系统上总共提供了4GB的可寻址空间,虚拟出的4GB空间并不都是给用户用的,而是分成两部分

    • 系统空间(程序进程不可访问),大小0x80000000~0xffffffff

    • 用户空间包括:栈、堆、全局静态数据&常量数据(地址从低到高),

      • 用户空间包括:代码区、静态(全局)数据区、动态数据区,动态数据又分为堆和栈。

堆喷射的底层原理在于javascript中所有的字符串通过堆保存,并且堆空间的增长是从低地址到高地址方向进行的,如果使用堆空间保存字符串数组,并且在该字符串数组中保存字符串,就会导致字符串在堆中从低地址到高地址依次占据内存空间,当该字符串足够长时,就会淹没高地址的堆空间导致溢出。

在实际中我们申请的堆内存为200MB,原因如下:

 0x0c0c0c0c=202116108大约等于192MB
所以只要堆喷大于200MB就能覆盖0c0c0c0c,而且分配地址并不是从0开始,所以实际中也并不需要这么大的内存

image.png

通过poc2代码进行验证,在javascript代码的图片元素中构造畸形图片路径导致eax内容为0x0c0c0c0c,最终导致在call函数调用ecx+18h(0x0c0c0c24)地址内容还是0x0c0c0c0c,此时CPU会执行指令0C0C0C0C,由于堆喷射已将地址为0x0c0c0c0c的内存空间全部填充为0C0C0C0C,0C0C0C0C在汇编中相当于or AL,0C,程序会一直执行直到遇到后续可执行的指令结束,最终导致程序崩溃。

那么漏洞利用,我们将0X0C0C0C0C地址所在的内存填充为shellcode即可达到漏洞利用的目的。此处的0C0C就相当于滑板指令,相当于nop,那么此处为什么不使用90作为滑板指令呢(之所以不使用nop作为本次攻击的滑板指令是因为nop指令对应的十六进制数据为0x90,如果将其作为堆喷射的内容,就需要将0x90数据淹没内存地址0x90909090,淹没该地址的需要申请更多的堆空间内存)。

分块堆喷

由于在JavaScript中多次申请内存获得的内存地址时不连续的,导致每个堆内存之间会有其他的代码存在,即可能程序中没有一个完整200MB大小的堆块供你申请,你所申请的堆块的大小可能小于200MB或者不是连续的200MB,此时堆块之间可能被其他数据结构隔开,导致利用失败。

分块堆喷就是为了解决以上问题,在内存分配中连续多次申请的堆空间地址是连续的这样就可以命中0C0C0C0C地址所在的内容,当然你也可以说在连续申请的时候中间也有被用掉的内存导致无法直接命中0C0C0C0C这种可能也是存在的,但是概率比较小,如果失败了,那么就重新申请一次即可。

  • 漏洞利用效果

    image.png
弹出计算器
image.png

WIN xp+IE8下漏洞利用

微软为IE8.0开启了数据执行保护技术(DEP),此时利用漏洞就需要绕过DEP。

DEP

DEP数据执行保护,是缓冲区溢出攻击出现后的一种防护机制,核心思想是将内存进行分块后设置不同的保护标志,令代码区拥有执行权限,而数据去只有读写权限,从而达到控制数据区域内的shellcode无法执行。

DEP的实现分两种方式:

  • 软件,由各种操作系统编译过程引入,在微软中叫SafeSEH。

  • 硬件,由英特尔这种CPU生产厂商固化到硬件中,也叫做NX保护机制。

由于DEP的存在,将堆栈页属性设置为不可执行,导致之前在堆空间0x0C0C0C0C地址上执行指令的操作无法实现,如果需要实现漏洞利用,需要需要设法绕过DEP机制。

绕过DEP

Return to lib

绕过DEP需要用到Ret2Libc(即Return to lib)技术, 即在程序栈中填充大量系统代码领空的地址,当程序以该地址作为函数地址执行或作为函数返回地址返回时,程序执行流程会从原程序代码领空跳转到系统代码领空,系统代码领空的地址所对应的指令的特征为总是以ret指令作为指令序列的结尾,从而当程序执行流执行完系统代码之后,会从栈顶取出函数的返回地址,继续执行该地址上的指令。

如果在系统代码领空找到此类指令,并将指令地址依次保存在栈中,程序就会依次执行系统代码领空的指令,通过规定指令执行的顺序,从而完成攻击操作,由完成攻击操作的指令序列也被称为Ret2Libc链。

如下图:

img

《0day》里面讲了3种思路突破DEP

  1. 通过跳转到ZwSetInformationProcess函数将DEP关闭,再转入shellcode

  2. 通过跳转到VirtualProtect函数来将shellcode所在内存页设置为可执行状态,再转入shellcode

  3. 通过跳转到VirtualAlloc函数开辟一段具有执行权限的内存空间,然后将shellcode复制到这段内存中执行。

  • 以上说了那么多我理解的意思是:

    1. 找到系统领空的以上三个函数,通过在栈中构造函数的参数使用对应函数修改或者关闭DEP。

    2. 通过poc2我们能够做到淹没栈中数据构造出精确的程序跳转位置,从而达到目的。

image.png

总结:通过上图我们分析到,ecx+18h处执行地址为0c0c0c0c处,但是由于存在DEP所以指令无法执行报错,使用Ret2Libc技术构造代码,让0c0c0c0c处跳转到代码可执行的空间(系统空间),从而达到命令执行的目的,但是此处需要精准的命中Ret2Libc的第一条指令才能成功。所以需要使用精准堆喷射技术达到这个目的。

精准堆喷

为了绕过 DEP,我们需要前面的Ret2Libc技术,另外,必须保证跳转到堆上的时候正好位于Ret2Libc链的第一条指令。因此需要使用精准堆喷射技术,才可以保证 0x0C0C0C0C 处即为Ret2Libc链的第一个字节。

  • 精准堆喷射的目的就是将指定内存地址处的值修改为指定内容,底层实现原理如下:

Windows使用内存分页机制管理内存,内存操作的最小单位为一个内存分页,一个内存分页4kb(0x1000)大小(64位系统中最大的内存分页为1G),则申请的一段堆空间中,堆空间首地址一定是0x1000的倍数,如果知道一个内存地址相对于其所在内存分页首地址的偏移,那么就可以构造一个内存分页大小的内存块,并在距离内存块首地址指定偏移的位置设置关键数据,然后以该内存块作为的最小单元进行堆喷,从而保证被内存堆喷射覆盖的指定内存地址处存在关键数据。

  • 看图说话比较直观,如下图,
image.png

详细解释:通过上文描述我们知道一个堆内存是多个内存分页组成,但是堆首地址并不是我们实际使用的首地址,我们进行堆喷射的首地址从UserPte开始,算出内存分页中的偏移,然后构造堆喷射内存分页时将Ret2Libc第一行代码加上偏移即可精确命中。

公式:相对偏移=(目标地址-UserPtr地址)%0x1000/2,其中目标地址就是关键数据内存地址(0c0c0c0c),和0x1000取余是为了确定在内存分页上的偏移(这样理解,减完算出来的偏移中间可能有好多个内存分页,取余之后就将所有的内存分页全部去掉了),除2是因为JavaScript中的字符串是Unicode。

然后就是精心构造Ret2Libc链,完成漏洞利用,整体来说整个堆喷的内存分页块如下图:

image.png

其中首尾的Padding部分用于占位,主要作用是保证整个数据块大小为0x1000,ROP Chain即为Ret2Libc链,而只执行恶意功能的ShellCode紧跟其后。

  • 以上就是精准堆喷的全部内容,通过精准堆喷能够让代码精准的命中Ret2Libc链的第一行代码,从而绕过DEP保护。

使用mona插件找到UserPtr地址与要使用系统空间代码。

先需要使用堆喷堆内存空间进行堆喷,否则地址0c0c0c0c的堆内存没有分配,获取不到UserPtr。

image.png

通过计算得到偏移为0x5F6。

image.png

在实际应用中0x40000个此类数据块(大小为256kb)被作为一个整体进行堆喷射,这样只需要将800个这样的数据块喷射到堆中,就可以形成202MB的数据,从而淹没地址0x0C0C0C0C。

image.png

在构造0x40000大小的数据块之后,根据网上资料显示,要为内存块保留0x2的块起始和0x21的块结尾的内存空间,所以需要截取0x40000大小的数据块的从0x2到0x39979大小的数据用以堆喷,应该与堆的内存分布有关。

image.png

注意: 这里使用substr的方法为字符串分配内存空间,是因为IE8.0对堆喷射做了一定的限制,采用直接字符串赋值进行堆喷的方法会被禁止。

精准堆喷射存在一定概率失败,不能将指定数据喷射到指定内存中,这种情况被称之为堆风水。不同的操作系统在不同浏览器进行堆喷射时,将块起始地址、块结尾、块大小按照指定方式进行设置成功率最高,该现象具体原因分析者仍不清楚。

Ret2Libc链的构造与绕过DEP
  • 先看构造好的指令代码

    • 地址 指令(系统空间) 用途
      0C0C0C0C RET指令地址 XCHG eax,esp ret指令执行之后的返回地址
      0C0C0C10 POP EBP;RET指令地址 主要用于将栈顶下移四位,将0C0C0C18设置为栈顶, 从而跳过0C0C0C14,不让XCHG eax,esp ret指令再次执行该处也可以为return 4指令的地址
      0C0C0C14 XCHG EAX,ESP;RET指令地址 call dword ptr [eax+8]指令触发,用于将执行流切换到栈上,也就是切换到0C0C0C0C所在的栈中
      0C0C0C18 RET指令地址
      0C0C0C1C RET指令地址
      0C0C0C20 RET指令地址
      0C0C0C24 RET指令地址 call dword ptr[ecx+18h]会调用这里,目的在于让指令继续在用户代码领空执行,需要触发call dword ptr [eax+8]
      0C0C0C28 ret2libc链 使用ret2libc链调用VirtualProtect,绕过edp,此处设置VirtualProtect函数地址,后面直接调用函数修改内存空间属性
死循环问题
  • 在构造Ret2Libc链之前先说下遇到的问题,死循环。
image.png
1.  首先,【XCHG EAX ESP;RET】指令是必须执行的,因为执行中需要指令引入到我们构造的栈中,也就是栈顶为0C0C0C0C栈。(此栈通过我们的堆喷内容构造而来)

2.  如上图,我们在执行指令1时,会在0x0C0C0C24的地址上取内容作为函数地址执行指令,如果此处保存【XCHG EAX ESP;RET】指令地址,就会执行这两条指令,执行之后,地址0x0C0C0C0C会变成栈顶(因为此时eax在指令3中被赋值为0x0C0C0C0C),RET指令会取0x0C0C0C0C地址中的内容赋值给eip作为函数地址执行。

3.  代码继续执行,那么此处0x0C0C0C0C地址中存放什么内容将至关重要。此处有一个逻辑需要整理下。

    *   eax来自于栈中的[EBP-14H],ecx来自于[eax],[ECX+18H]=[0C0C0C0C+18H]存放【XCHG EAX ESP;RET】,所以反推回去,eax中只能存放0C0C0C0C。

4.  **那么问题来了**,如果构造的堆栈中的0C0C0C0C中存放着0C0C0C0C,在【XCHG EAX ESP;RET】执行完后将0C0C0C0C作为函数地址指令执行,此时0C0C0C0C的地址空间受DEP保护,所以程序崩溃。

*   **有没有发现这是一个死循环**
  • 通过栈溢出修改溢出数据,(未)解决死循环

    (不知道第一个想出这种办法的人是有多厉害)

    在构造畸形路径进行栈溢出时不使用0x0C0C0C0C进行栈溢出,而是用0x0C0C0C08进行栈溢出。(此处注意时进行栈溢出而不是进行堆溢出)。

    还是如上我们屡屡此处的逻辑:

    • 我们使用0x0C0C0C08继续栈溢出,所以eax=0x0C0C0C08,ecx=[eax]=0x0C0C0C0C

    • call [ecx+18h]->call [0x0C0C0C0C+18h]->执行【XCHG EAX ESP;RET】

    • 当执行完指令后和之前的操作一样了,还是造成死循环

  • 利用其他汇编指令,解决死循环

image.png

在前面的栈溢出的基础上,无法在call dword ptr[ecx+18h]解决死循环问题,我们可以修改指令1中的汇编指令,为将0x0C0C0C24地址上的内容替换为ret指令所在的内存空间的地址,当程序执行到call dword ptr[ecx+18h]时继续在用户代码空间执行,直到执行指令5:call dword ptr [eax+8]。

  • 以下详细分析指令5,

    • esi最初来自于eax,esi=0x0C0C0C08,[esi]=eax=0x0C0C0C0C,eax+8=0x0C0C0C14,我们在0x0C0C0C14处执行【XCHG EAX ESP;RET】执行,将代码切换到构造的栈上,栈顶为ESP=0C0C0C0C
    image.png
*   栈顶指令为RET,简单理解,之后的指令执行都是在我们构造的栈中进行

*   【POP EBP;RET】指令,我的理解,主要是POP EBP命令为了将栈顶设置为0x0C0C0C18,从而跳过0x0C0C0C14

*   后面的RET指令相当于滑板指令,将栈依次减小直到执行ret2libc链,对堆空间属性进行修改,从而绕过DEP。

ret2libc链的具体结构:

地址 指令(系统空间) 用途
0C0C0C28 VritualProtect函数的地址 进行DEP绕过使用函数(从30开始以下4个都为函数参数)
0C0C0C2C payload的首地址 作为VritualProtect函数返回地址,执行恶意代码
0C0C0C30 要修改内存空间首地址 参数1,payload的首地址
0C0C0C34 要修改内存空间的大小 参数2,payload大小0x1000即可
0C0C0C38 目的内存属性 参数3,可读可执行
0C0C0C3C 原始内存属性的保存地址 参数4,只要一个可写地址即可
0C0C0C40 payload的起始地址
  • payload地址直接计算得到,0C0C0C3c+4=0C0C0C40。

  • 以下在系统空间寻找指令操作

查找UserPtr之前已经讨论过,此处不再赘述。

查看系统模块信息

image.png

查找VirtualProtect函数地址u kernel32!VirtualProtect(查找指定模块的函数地址,当然还有其他很多命令,此处只是用一个)

image.png

还有其他指令,如:

!py mond find –s “\x5d\xc3”–mmsvcrt.dll 查找 POP EBP; RET指令序列。

!py monafind –s “\x94\xC3” –m msvcrt.dll ,查找XCHGEAX,ESP;RET指令序列。

!py mond find –s “\xc3” –mmsvcrt.dll,查找RET指令。

当然也可以在其他模块中查找。

  • 通过以上分析,我们通过构造ret2libc链,最终绕过DEP保护,实现漏洞利用。
image.png

WIN7+IE8漏洞利用

在该版本漏洞利用中,即开启了DEP,也开启了ASLR。

  • ASLR:地址空间布局随机化(Address space layout randomization,ASLR)是微软从Windows Vista开始加入的一种安全保护技术,它通过随机化几乎是所有模块的加载地址,使得预测指定地址或者使用指定地址的代码变成了一件十分困难的事,在本次漏洞利用过程中,通过前面的学习大家应该知道,要绕过DEP,就需要构造Ret2Libc链,而构造Ret2Libc链的基础就是需要使用一些固定指令的地址,如果程序的加载基址随机化,就无法以固定的地址寻址特定指令序列,进而无法构成Ret2Libc链。
绕过ASLR的方法:
  1. 找到程序进程中没有开启随即基址的模块,比如java的运行环境、FlashPlayer,使用此类模块中的序列构造Ret2Libc链。

  2. 使用堆喷射,可以控制任意地址中的任意内容,不受随机基址影响。

  3. 利用操作系统中的固定点,3环中部分函数的地址是不变的,通过分析windows源码,有的函数定义的时候是个宏,说明其地址是固定的,如果知道该地址,可以进行利用。

  4. Intel的cpu使用小端保存数据,高位数据保存在内存高地址,低位数据保存在内存低地址,随机基址只能将内存地址中的基址随机化,无法随机相对虚拟地址rva,通过淹没一个地址的低十六位,即只修改rva,可以绕过随机基址,从而访问到指定内存位置。

  • 解析:

    • 对于第二种绕过随机基址方式,因为win7+ie8环境下默认开启了DEP,所以无法在堆空间执行指令,如果需要关闭堆空间,前提就是构造Ret2Libc链,而随机基址使得该前提无法达成,故该方法失效。

    • 对于第三种方法,分析者仍不清楚此类函数的具体内容,故无法使用该方法。

    • 对于第四种方法,其方法奏效的前提是特定的函数地址的基址需要由程序自身根据当前的实际加载基址进行填充,本漏洞利用过程中所执行的代码均位于堆空间,程序自身无法影响该部分代码的内容,故此方法失效。

    综上,在Win7+IE8环境下,如果需要实现绕过ASLR,需要浏览器本身安装特定插件,此类插件中存在未开启随机基址的模块,并通过mona查询该模块中的特定指令序列的地址,以此构造Ret2Libc链,主要思路与之前xp+ie8的漏洞利用相似,故不再赘述

4.附件POC

winXP+IE6.0

漏洞验证poc1:


 
  CVE 2012-1889 PoC v1 By:15PB.Com
 
 
  
  
  
  
 
 

使用0C0C0C0C填充poc2:


 
  CVE 2012-1889 PoC v1 By:15PB.Com
 
 
  
  
  
  
 
 

exp漏洞利用:


 
 CVE 2012-1889 POC Red_Magic_ver.7
 
 
 
 
 
 
 
 

winXP+IE8

EXP漏洞利用:


 [/align][/align][align=left] 
 CVE 2012-1889 POC Red_Magic_ver.7
 
 
 
 
 
 

5.总结

通过本次的漏洞分析,掌握了基本的漏洞分析方式与防护措施的绕过技术,了解到了防护技术的底层含义,对以后的漏洞分析还是有很大的帮助,暴雷漏洞是一个比较老比较基础的漏洞,但是基础的简单的才是最本质最底层的,其中的每一项技术都是值得去深挖和研究的,本次分析也提高了自身对底层只是与汇编的理解,同时也看到了自己的不足之处,对以后分析高难度的漏洞打好了基础。

6.参考资料

[1] 任晓辉.《15PB信息安全教育:shellcode编程艺术》.2017-06-15.

[2] 北海松果.《暴雷漏洞(CVE-2012-1889)个人漏洞分析报告》.看雪论坛.2017-07-15。地址:https://bbs.pediy.com/thread-219222.htm

[3]《Microsoft XML Core Services缓冲区溢出漏洞(CVE-2012-1889)漏洞分析报告》.吾爱破解。地址:https://www.52pojie.cn/thread-730324-1-1.html

[4] seviezhou. 《32位下的堆喷射技术》.安全客.2017-10-20。

地址:https://www.anquanke.com/post/id/87048

[5] fdgnneig. 《暴雷漏洞(CVE-2012-1889)分析报告》.博客园。

地址:https://www.cnblogs.com/hell--world/p/11531066.html

你可能感兴趣的:(暴雷漏洞(CVE-2012-1889)分析报告)