From 03f4ce7127c9640e8186711f1644eaa58fdb0b99 Mon Sep 17 00:00:00 2001 From: Dean Welch Date: Thu, 2 May 2024 13:57:13 +0100 Subject: [PATCH] Convert ldap modules to use the new ldap session type --- .../core/exploit/remote/kerberos/client.rb | 16 ++-- lib/msf/core/exploit/remote/ldap.rb | 12 +-- lib/msf/core/optional_session/ldap.rb | 33 +++++-- lib/rex/proto/kerberos/client.rb | 2 +- .../admin/ldap/ad_cs_cert_template.rb | 1 + modules/auxiliary/admin/ldap/rbcd.rb | 1 + .../admin/ldap/shadow_credentials.rb | 1 + .../ldap/vmware_vcenter_vmdir_auth_bypass.rb | 9 +- modules/auxiliary/gather/asrep.rb | 9 +- .../gather/ldap_esc_vulnerable_cert_finder.rb | 3 +- modules/auxiliary/gather/ldap_hashdump.rb | 39 +++++---- modules/auxiliary/gather/ldap_query.rb | 1 + .../gather/vmware_vcenter_vmdir_ldap.rb | 29 ++++--- spec/acceptance/ldap_spec.rb | 29 ++++++- spec/lib/msf/core/exploit/remote/ldap_spec.rb | 87 ------------------- spec/lib/rex/proto/kerberos/client_spec.rb | 44 +++++++++- 16 files changed, 167 insertions(+), 149 deletions(-) diff --git a/lib/msf/core/exploit/remote/kerberos/client.rb b/lib/msf/core/exploit/remote/kerberos/client.rb index 1a2d36bd0a8d3..358cf60dec133 100644 --- a/lib/msf/core/exploit/remote/kerberos/client.rb +++ b/lib/msf/core/exploit/remote/kerberos/client.rb @@ -27,7 +27,7 @@ module Client # @!attribute client # @return [Rex::Proto::Kerberos::Client] The kerberos client - attr_accessor :client + attr_accessor :kerberos_client def initialize(info = {}) super @@ -96,8 +96,8 @@ def connect(opts={}) protocol: 'tcp' ) - disconnect if client - self.client = kerb_client + disconnect if kerberos_client + self.kerberos_client = kerb_client kerb_client end @@ -105,11 +105,11 @@ def connect(opts={}) # Disconnects the Kerberos client # # @param kerb_client [Rex::Proto::Kerberos::Client] the client to disconnect - def disconnect(kerb_client = client) + def disconnect(kerb_client = kerberos_client) kerb_client.close if kerb_client - if kerb_client == client - self.client = nil + if kerb_client == kerberos_client + self.kerberos_client = nil end end @@ -129,7 +129,7 @@ def cleanup def send_request_as(opts = {}) connect(opts) req = opts.fetch(:req) { build_as_request(opts) } - res = client.send_recv(req) + res = kerberos_client.send_recv(req) disconnect res end @@ -143,7 +143,7 @@ def send_request_as(opts = {}) def send_request_tgs(opts = {}) connect(opts) req = opts.fetch(:req) { build_tgs_request(opts) } - res = client.send_recv(req) + res = kerberos_client.send_recv(req) disconnect res end diff --git a/lib/msf/core/exploit/remote/ldap.rb b/lib/msf/core/exploit/remote/ldap.rb index 62f8cca893032..3c203a49be118 100644 --- a/lib/msf/core/exploit/remote/ldap.rb +++ b/lib/msf/core/exploit/remote/ldap.rb @@ -12,7 +12,6 @@ module Exploit::Remote::LDAP include Msf::Exploit::Remote::Kerberos::Ticket::Storage include Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Options include Metasploit::Framework::LDAP::Client - include Msf::OptionalSession::LDAP # Initialize the LDAP client and set up the LDAP specific datastore # options to allow the client to perform authentication and timeout @@ -28,6 +27,8 @@ def initialize(info = {}) super register_options([ + Opt::RHOST, + Opt::RPORT(389), OptBool.new('SSL', [false, 'Enable SSL on the LDAP connection', false]), Msf::OptString.new('DOMAIN', [false, 'The domain to authenticate to']), Msf::OptString.new('USERNAME', [false, 'The username to authenticate with'], aliases: ['BIND_DN']), @@ -95,7 +96,6 @@ def get_connect_opts # @return [Object] The result of whatever the block that was # passed in via the "block" parameter yielded. def ldap_connect(opts = {}, &block) - return yield session.client if session ldap_open(get_connect_opts.merge(opts), &block) end @@ -111,7 +111,6 @@ def ldap_connect(opts = {}, &block) # @return [Object] The result of whatever the block that was # passed in via the "block" parameter yielded. def ldap_open(connect_opts, &block) - return yield session.client if session opts = resolve_connect_opts(connect_opts) Rex::Proto::LDAP::Client.open(opts, &block) end @@ -136,8 +135,6 @@ def resolve_connect_opts(connect_opts) # @yieldparam ldap [Rex::Proto::LDAP::Client] The LDAP connection handle to use for connecting to # the target LDAP server. def ldap_new(opts = {}) - return yield session.client if session - ldap = Rex::Proto::LDAP::Client.new(resolve_connect_opts(get_connect_opts.merge(opts))) # NASTY, but required @@ -182,6 +179,11 @@ def ldap.use_connection(args) # bind request failed. # @return [Nil] This function does not return any data. def validate_bind_success!(ldap) + if defined?(:session) && session + vprint_good('Successfully bound to the LDAP server via existing SESSION!') + return + end + bind_result = ldap.get_operation_result.table # Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes diff --git a/lib/msf/core/optional_session/ldap.rb b/lib/msf/core/optional_session/ldap.rb index 58b47b503e8bb..61b6c1d2a898b 100644 --- a/lib/msf/core/optional_session/ldap.rb +++ b/lib/msf/core/optional_session/ldap.rb @@ -34,19 +34,38 @@ def initialize(info = {}) ) add_info('New in Metasploit 6.4 - This module can target a %grnSESSION%clr or an %grnRHOST%clr') - else - register_options( - [ - Msf::Opt::RHOST, - Msf::Opt::RPORT(389), - ] - ) end end def optional_session_enabled? framework.features.enabled?(Msf::FeatureManager::LDAP_SESSION_TYPE) end + + # @see #ldap_open + # @return [Object] The result of whatever the block that was + # passed in via the "block" parameter yielded. + def ldap_connect(opts = {}, &block) + if session && !opts[:base].blank? + session.client.base = opts[:base] + end + return yield session.client if session + ldap_open(get_connect_opts.merge(opts), &block) + end + + # Create a new LDAP connection using Rex::Proto::LDAP::Client.new and yield the + # resulting connection object to the caller of this method. + # + # @param opts [Hash] A hash containing the connection options for the + # LDAP connection to the target server. + # @yieldparam ldap [Rex::Proto::LDAP::Client] The LDAP connection handle to use for connecting to + # the target LDAP server. + def ldap_new(opts = {}) + if session && !opts[:base].blank? + session.client.base = opts[:base] + end + return yield session.client if session + super + end end end end diff --git a/lib/rex/proto/kerberos/client.rb b/lib/rex/proto/kerberos/client.rb index 4d0669d662bfc..a4779ad177b62 100644 --- a/lib/rex/proto/kerberos/client.rb +++ b/lib/rex/proto/kerberos/client.rb @@ -45,7 +45,7 @@ def initialize(opts = {}) # @raise [RuntimeError] if the connection can not be created def connect return connection if connection - + raise ArgumentError, 'Missing remote address' unless self.host && self.port case protocol when 'tcp' self.connection = create_tcp_connection diff --git a/modules/auxiliary/admin/ldap/ad_cs_cert_template.rb b/modules/auxiliary/admin/ldap/ad_cs_cert_template.rb index f76d5bac66ee7..eda209602497f 100644 --- a/modules/auxiliary/admin/ldap/ad_cs_cert_template.rb +++ b/modules/auxiliary/admin/ldap/ad_cs_cert_template.rb @@ -6,6 +6,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP include Msf::Auxiliary::Report IGNORED_ATTRIBUTES = [ diff --git a/modules/auxiliary/admin/ldap/rbcd.rb b/modules/auxiliary/admin/ldap/rbcd.rb index 3abfb6375d640..06bf7ddd3ae54 100644 --- a/modules/auxiliary/admin/ldap/rbcd.rb +++ b/modules/auxiliary/admin/ldap/rbcd.rb @@ -6,6 +6,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP ATTRIBUTE = 'msDS-AllowedToActOnBehalfOfOtherIdentity'.freeze diff --git a/modules/auxiliary/admin/ldap/shadow_credentials.rb b/modules/auxiliary/admin/ldap/shadow_credentials.rb index ab4060dff428a..5d17a6ca8d442 100644 --- a/modules/auxiliary/admin/ldap/shadow_credentials.rb +++ b/modules/auxiliary/admin/ldap/shadow_credentials.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP ATTRIBUTE = 'msDS-KeyCredentialLink'.freeze diff --git a/modules/auxiliary/admin/ldap/vmware_vcenter_vmdir_auth_bypass.rb b/modules/auxiliary/admin/ldap/vmware_vcenter_vmdir_auth_bypass.rb index 2856d35f4880d..b5b6fa9b99e61 100644 --- a/modules/auxiliary/admin/ldap/vmware_vcenter_vmdir_auth_bypass.rb +++ b/modules/auxiliary/admin/ldap/vmware_vcenter_vmdir_auth_bypass.rb @@ -6,6 +6,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP include Msf::Exploit::Remote::CheckModule def initialize(info = {}) @@ -42,6 +43,7 @@ def initialize(info = {}) 'DefaultAction' => 'Add', 'DefaultOptions' => { 'SSL' => true, + 'RPORT' => 636, # SSL/TLS 'CheckModule' => 'auxiliary/gather/vmware_vcenter_vmdir_ldap' }, 'Notes' => { @@ -53,10 +55,9 @@ def initialize(info = {}) ) register_options([ - Opt::RPORT(636), # SSL/TLS OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']), - OptString.new('NEW_USERNAME', [false, 'Username of admin user to add']), - OptString.new('NEW_PASSWORD', [false, 'Password of admin user to add']) + OptString.new('NEW_USERNAME', [true, 'Username of admin user to add']), + OptString.new('NEW_PASSWORD', [true, 'Password of admin user to add']) ]) end @@ -99,7 +100,7 @@ def run end ldap_connect do |ldap| - print_status("Bypassing LDAP auth in vmdir service at #{peer}") + print_status("Bypassing LDAP auth in vmdir service at #{ldap.peerinfo}") auth_bypass(ldap) print_status("Adding admin user #{new_username} with password #{new_password}") diff --git a/modules/auxiliary/gather/asrep.rb b/modules/auxiliary/gather/asrep.rb index 150a3012ecb24..15e12666dfb96 100644 --- a/modules/auxiliary/gather/asrep.rb +++ b/modules/auxiliary/gather/asrep.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::Kerberos::Client include Msf::Exploit::Remote::LDAP include Msf::Exploit::Remote::LDAP::Queries + include Msf::OptionalSession::LDAP def initialize(info = {}) super( @@ -42,11 +43,16 @@ def initialize(info = {}) register_options( [ + Opt::RHOSTS(nil, true, 'The target KDC, see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html'), OptPath.new('USER_FILE', [ false, 'File containing usernames, one per line' ], conditions: %w[ACTION == BRUTE_FORCE]), OptBool.new('USE_RC4_HMAC', [ true, 'Request using RC4 hash instead of default encryption types (faster to crack)', true]), OptString.new('Rhostname', [ true, "The domain controller's hostname"], aliases: ['LDAP::Rhostname']), ] ) + register_option_group(name: 'SESSION', + description: 'Used when connecting to LDAP over an existing SESSION', + option_names: %w[RHOSTS], + required_options: %w[SESSION RHOSTS]) register_advanced_options( [ OptEnum.new('LDAP::Auth', [true, 'The Authentication mechanism to use', Msf::Exploit::Remote::AuthOption::NTLM, Msf::Exploit::Remote::AuthOption::LDAP_OPTIONS]), @@ -136,7 +142,8 @@ def roast(username) client_name: username, realm: datastore['DOMAIN'], offered_etypes: etypes, - rport: 88 + rport: 88, + rhost: datastore['RHOST'] ) hash = format_as_rep_to_john_hash(res.as_rep) print_line(hash) diff --git a/modules/auxiliary/gather/ldap_esc_vulnerable_cert_finder.rb b/modules/auxiliary/gather/ldap_esc_vulnerable_cert_finder.rb index fc2a82d237c54..01e670c31c4bc 100644 --- a/modules/auxiliary/gather/ldap_esc_vulnerable_cert_finder.rb +++ b/modules/auxiliary/gather/ldap_esc_vulnerable_cert_finder.rb @@ -1,6 +1,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP ADS_GROUP_TYPE_BUILTIN_LOCAL_GROUP = 0x00000001 ADS_GROUP_TYPE_GLOBAL_GROUP = 0x00000002 @@ -459,7 +460,7 @@ def run else print_status('Discovering base DN automatically') - unless (@base_dn = discover_base_dn(ldap)) + unless (@base_dn = ldap.base_dn) fail_with(Failure::NotFound, "Couldn't discover base DN!") end end diff --git a/modules/auxiliary/gather/ldap_hashdump.rb b/modules/auxiliary/gather/ldap_hashdump.rb index 9d7ebea25b139..118aa0f7a1f11 100644 --- a/modules/auxiliary/gather/ldap_hashdump.rb +++ b/modules/auxiliary/gather/ldap_hashdump.rb @@ -8,6 +8,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP def initialize(info = {}) super( @@ -68,7 +69,7 @@ def print_ldap_error(ldap) unless opres.error_message.to_s.empty? msg += " - #{opres.error_message}" end - print_error("#{peer} #{msg}") + print_error("#{ldap.peerinfo} #{msg}") end # PoC using ldapsearch(1): @@ -85,26 +86,28 @@ def run_host(ip) entries_returned = 0 - print_status("#{peer} Connecting...") ldap_new do |ldap| if ldap.get_operation_result.code == 0 - vprint_status("#{peer} LDAP connection established") + vprint_status("#{ldap.peerinfo} LDAP connection established") else # Even if we get "Invalid credentials" error, we may proceed with anonymous bind print_ldap_error(ldap) end + @rhost = ldap.peerhost + @rport = ldap.peerport + if (base_dn_tmp = datastore['BASE_DN']) - vprint_status("#{peer} User-specified base DN: #{base_dn_tmp}") + vprint_status("#{ldap.peerinfo} User-specified base DN: #{base_dn_tmp}") naming_contexts = [base_dn_tmp] else - vprint_status("#{peer} Discovering base DN(s) automatically") + vprint_status("#{ldap.peerinfo} Discovering base DN(s) automatically") naming_contexts = ldap.naming_contexts print_ldap_error(ldap) unless ldap.get_operation_result.code == 0 if naming_contexts.nil? || naming_contexts.empty? - vprint_warning("#{peer} Falling back to an empty base DN") + vprint_warning("#{ldap.peerinfo} Falling back to an empty base DN") naming_contexts = [''] end end @@ -113,14 +116,14 @@ def run_host(ip) @user_attr ||= datastore['USER_ATTR'] @user_attr ||= 'dn' - vprint_status("#{peer} Taking '#{@user_attr}' attribute as username") + vprint_status("#{ldap.peerinfo} Taking '#{@user_attr}' attribute as username") pass_attr ||= datastore['PASS_ATTR'] @pass_attr_array = pass_attr.split(/[,\s]+/).compact.reject(&:empty?).map(&:downcase) # Dump root DSE for useful information, e.g. dir admin if @max_loot.nil? || (@max_loot > 0) - print_status("#{peer} Dumping data for root DSE") + print_status("#{ldap.peerinfo} Dumping data for root DSE") ldap_search(ldap, 'root DSE', { ignore_server_caps: true, @@ -129,7 +132,7 @@ def run_host(ip) end naming_contexts.each do |base_dn| - print_status("#{peer} Searching base DN='#{base_dn}'") + print_status("#{ldap.peerinfo} Searching base DN='#{base_dn}'") entries_returned += ldap_search(ldap, base_dn, { base: base_dn }) @@ -155,7 +158,7 @@ def ldap_search(ldap, base_dn, args) attributes: %w[* + -] } Tempfile.create do |f| - f.write("# LDIF dump of #{peer}, base DN='#{base_dn}'\n") + f.write("# LDIF dump of #{ldap.peerinfo}, base DN='#{base_dn}'\n") f.write("\n") begin # HACK: fix lack of read/write timeout in Net::LDAP @@ -175,18 +178,18 @@ def ldap_search(ldap, base_dn, args) end end rescue Timeout::Error - print_error("#{peer} Host timeout reached while searching '#{base_dn}'") + print_error("#{ldap.peerinfo} Host timeout reached while searching '#{base_dn}'") return entries_returned ensure unless ldap.get_operation_result.code == 0 print_ldap_error(ldap) end if entries_returned > 0 - print_status("#{peer} #{entries_returned} entries, #{creds_found} creds found in '#{base_dn}'.") + print_status("#{ldap.peerinfo} #{entries_returned} entries, #{creds_found} creds found in '#{base_dn}'.") f.rewind pillage(f.read, base_dn) elsif ldap.get_operation_result.code == 0 - print_error("#{peer} No entries returned for '#{base_dn}'.") + print_error("#{ldap.peerinfo} No entries returned for '#{base_dn}'.") end end end @@ -194,7 +197,7 @@ def ldap_search(ldap, base_dn, args) end def pillage(ldif, base_dn) - vprint_status("#{peer} Storing LDAP data for base DN='#{base_dn}' in loot") + vprint_status("Storing LDAP data for base DN='#{base_dn}' in loot") ltype = base_dn.clone ltype.gsub!(/ /, '_') @@ -213,11 +216,11 @@ def pillage(ldif, base_dn) ) unless ldif_filename - print_error("#{peer} Could not store LDAP data in loot") + print_error('Could not store LDAP data in loot') return end - print_good("#{peer} Saved LDAP data to #{ldif_filename}") + print_good("Saved LDAP data to #{ldif_filename}") end def decode_pwdhistory(hash) @@ -243,7 +246,7 @@ def process_hash(entry, attr) module_fullname: fullname, origin_type: :service, address: @rhost, - port: rport, + port: @rport, protocol: 'tcp', service_name: 'ldap' } @@ -359,7 +362,7 @@ def process_hash(entry, attr) # highlight unresolved hashes hash_format = '{crypt}' if hash =~ /{crypt}/i - print_good("#{peer} Credentials (#{hash_format.empty? ? 'password' : hash_format}) found in #{attr}: #{dn}:#{hash}") + print_good("#{@rhost}:#{@rport} Credentials (#{hash_format.empty? ? 'password' : hash_format}) found in #{attr}: #{dn}:#{hash}") # known hash types should have been identified, # let's assume the rest are clear text passwords diff --git a/modules/auxiliary/gather/ldap_query.rb b/modules/auxiliary/gather/ldap_query.rb index 49068b3f37235..0819ebdbe3e3f 100644 --- a/modules/auxiliary/gather/ldap_query.rb +++ b/modules/auxiliary/gather/ldap_query.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP include Msf::Exploit::Remote::LDAP::Queries + include Msf::OptionalSession::LDAP require 'json' require 'yaml' diff --git a/modules/auxiliary/gather/vmware_vcenter_vmdir_ldap.rb b/modules/auxiliary/gather/vmware_vcenter_vmdir_ldap.rb index efc3316be489a..fc9b95b2ede9b 100644 --- a/modules/auxiliary/gather/vmware_vcenter_vmdir_ldap.rb +++ b/modules/auxiliary/gather/vmware_vcenter_vmdir_ldap.rb @@ -6,6 +6,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::LDAP + include Msf::OptionalSession::LDAP include Msf::Auxiliary::Report def initialize(info = {}) @@ -37,7 +38,8 @@ def initialize(info = {}) ], 'DefaultAction' => 'Dump', 'DefaultOptions' => { - 'SSL' => true + 'SSL' => true, + 'RPORT' => 636 }, 'Notes' => { 'Stability' => [CRASH_SAFE], @@ -48,7 +50,6 @@ def initialize(info = {}) ) register_options([ - Opt::RPORT(636), # SSL/TLS OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']) ]) end @@ -82,25 +83,25 @@ def run end end - print_status("Dumping LDAP data from vmdir service at #{peer}") + print_status("Dumping LDAP data from vmdir service at #{ldap.peerinfo}") # A "-" meta-attribute will dump userPassword (hat tip Hynek) # https://github.com/vmware/lightwave/blob/3bc154f823928fa0cf3605cc04d95a859a15c2a2/vmdir/server/ldap-head/result.c#L647-L654 entries = ldap.search(base: base_dn, attributes: %w[* + -]) - end - # Look for an entry with a non-empty vmwSTSPrivateKey attribute - unless entries&.find { |entry| entry[:vmwstsprivatekey].any? } - print_error("#{peer} is NOT vulnerable to CVE-2020-3952") unless datastore['BIND_PW'].present? - print_error('Dump failed') - return Exploit::CheckCode::Safe - end + # Look for an entry with a non-empty vmwSTSPrivateKey attribute + unless entries&.find { |entry| entry[:vmwstsprivatekey].any? } + print_error("#{ldap.peerinfo} is NOT vulnerable to CVE-2020-3952") unless datastore['BIND_PW'].present? + print_error('Dump failed') + return Exploit::CheckCode::Safe + end - print_good("#{peer} is vulnerable to CVE-2020-3952") unless datastore['BIND_PW'].present? - pillage(entries) + print_good("#{ldap.peerinfo} is vulnerable to CVE-2020-3952") unless datastore['BIND_PW'].present? + pillage(entries) - # HACK: Stash discovered base DN in CheckCode reason - Exploit::CheckCode::Vulnerable(base_dn) + # HACK: Stash discovered base DN in CheckCode reason + Exploit::CheckCode::Vulnerable(base_dn) + end rescue Net::LDAP::Error => e print_error("#{e.class}: #{e.message}") Exploit::CheckCode::Unknown diff --git a/spec/acceptance/ldap_spec.rb b/spec/acceptance/ldap_spec.rb index 52684c859b8e5..dbe17ae33c597 100644 --- a/spec/acceptance/ldap_spec.rb +++ b/spec/acceptance/ldap_spec.rb @@ -87,7 +87,34 @@ ] } } - } + }, + { + name: 'auxiliary/gather/ldap_esc_vulnerable_cert_finder', + platforms: %i[linux osx windows], + targets: [:session, :rhost], + skipped: false, + lines: { + all: { + required: [ + /Successfully queried/ + ] + } + } + }, + { + name: 'auxiliary/admin/ldap/rbcd', + platforms: %i[linux osx windows], + targets: [:session, :rhost], + skipped: false, + datastore: { DELEGATE_TO: 'administrator' }, + lines: { + all: { + required: [ + /The msDS-AllowedToActOnBehalfOfOtherIdentity field is empty./ + ] + } + } + }, ] } } diff --git a/spec/lib/msf/core/exploit/remote/ldap_spec.rb b/spec/lib/msf/core/exploit/remote/ldap_spec.rb index ebf6abb987751..3933792d2adfe 100644 --- a/spec/lib/msf/core/exploit/remote/ldap_spec.rb +++ b/spec/lib/msf/core/exploit/remote/ldap_spec.rb @@ -117,91 +117,4 @@ end end end - - # describe '#get_naming_contexts' do - # let(:ldap) do - # instance_double(Net::LDAP) - # end - # context 'Could not retrieve root DSE' do - # it do - # expect(ldap).to receive(:search_root_dse).and_return(false) - # expect(subject.get_naming_contexts(ldap)).to be(nil) - # end - # end - - # context 'Empty naming contexts' do - # let(:root_dse) do - # { namingcontexts: [] } - # end - # it do - # expect(ldap).to receive(:search_root_dse).and_return(root_dse) - # expect(subject.get_naming_contexts(ldap)).to be(nil) - # end - # end - - # context 'Naming contexts are present' do - # - # let(:naming_contexts) { - # %w[context1 context2] - # } - # - # let(:root_dse) do - # { namingcontexts: naming_contexts } - # end - # - # it do - # expect(ldap).to receive(:search_root_dse).and_return(root_dse) - # expect(subject.get_naming_contexts(ldap)).to be(naming_contexts) - # end - # end - # end - - # describe '#discover_base_dn' do - # let(:ldap) do - # instance_double(Net::LDAP) - # end - # - # context 'No naming contexts' do - # it do - # expect(subject).to receive(:get_naming_contexts).with(ldap).and_return(nil) - # expect(subject.discover_base_dn(ldap)).to be(nil) - # end - # end - # - # context 'Invalid naming contexts' do - # let(:invalid_naming_contexts) do - # %w[invalid1 invalid2] - # end - # it do - # expect(subject).to receive(:get_naming_contexts).with(ldap).and_return(invalid_naming_contexts) - # expect(subject.discover_base_dn(ldap)).to be(nil) - # end - # end - # - # context 'Valid naming contexts' do - # let(:base_dn) do - # 'DC=abcdef' - # end - # let(:valid_naming_contexts) do - # [base_dn] - # end - # it do - # expect(subject).to receive(:get_naming_contexts).with(ldap).and_return(valid_naming_contexts) - # expect(subject.discover_base_dn(ldap)).to be(base_dn) - # end - # end - # - # context 'Valid naming contexts (lowercase dc)' do - # let(:base_dn) do - # 'dc=abcdef' - # end - # let(:valid_naming_contexts) do - # [base_dn] - # end - # it do - # expect(subject).to receive(:get_naming_contexts).with(ldap).and_return(valid_naming_contexts) - # expect(subject.discover_base_dn(ldap)).to be(base_dn) - # end - # end - # end end diff --git a/spec/lib/rex/proto/kerberos/client_spec.rb b/spec/lib/rex/proto/kerberos/client_spec.rb index 2d52e28718a11..1d396f44025c4 100644 --- a/spec/lib/rex/proto/kerberos/client_spec.rb +++ b/spec/lib/rex/proto/kerberos/client_spec.rb @@ -22,8 +22,15 @@ def get_once(length, timeout = 10) end end + let(:rhost) { '127.0.0.1' } + let(:rport) { 88 } + subject(:client) do - described_class.new + opts = { + host: rhost, + port: rport, + } + described_class.new(opts) end let(:sample_asn1_request) do @@ -117,6 +124,40 @@ def get_once(length, timeout = 10) end end + describe '#connect' do + context 'when no host is specified' do + + subject do + opts = { + port: rport, + } + described_class.new(opts) + end + + it 'should raise an argument error' do + expect { subject.connect }.to raise_error(::ArgumentError) + end + end + + context 'when no port is specified' do + subject do + opts = { + host: rhost, + } + described_class.new(opts) + end + it 'should raise an argument error' do + expect { subject.connect }.not_to raise_error + end + end + + context 'when host and port are specified' do + it 'should not raise an error' do + expect { subject.connect }.not_to raise_error + end + end + end + describe "#recv_response" do context "when no connection" do it "raises RunitmeError" do @@ -154,4 +195,3 @@ def get_once(length, timeout = 10) end end end -