Skip to content

Commit

Permalink
Change how ldap_login generate its specific credentials for SCHANNEL …
Browse files Browse the repository at this point in the history
…&& KERBEROS auth
  • Loading branch information
Mathiou04 committed Feb 12, 2025
1 parent 66ce020 commit b08a5f6
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 89 deletions.
30 changes: 2 additions & 28 deletions lib/metasploit/framework/credential_collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,23 +212,6 @@ class CredentialCollection < PrivateCredentialCollection
# @return [Boolean]
attr_accessor :anonymous_login

# @!attribute ignore_private
# Whether to ignore private (password). This is usually set when Kerberos
# or Schannel authentication is requested and the credentials are
# retrieved from cache or from a file. This attribute should be true in
# these scenarios, otherwise validation will fail since the password is not
# provided.
# @return [Boolean]
attr_accessor :ignore_private

# @!attribute ignore_public
# Whether to ignore public (username). This is usually set when Schannel
# authentication is requested and the credentials are retrieved from a
# file (certificate). This attribute should be true in this case,
# otherwise validation will fail since the password is not provided.
# @return [Boolean]
attr_accessor :ignore_public

# @option opts [Boolean] :blank_passwords See {#blank_passwords}
# @option opts [String] :pass_file See {#pass_file}
# @option opts [String] :password See {#password}
Expand Down Expand Up @@ -267,15 +250,6 @@ def each_filtered
alias each each_filtered

def each_unfiltered(&block)
if ignore_private
if ignore_public
yield Metasploit::Framework::Credential.new(public: nil, private: nil, realm: realm)
else
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm)
end
return
end

prepended_creds.each { |c| yield c }

if anonymous_login
Expand Down Expand Up @@ -468,14 +442,14 @@ def empty?
#
# @return [Boolean]
def has_users?
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty? || !!ignore_public
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty?
end

# Returns true when there are any private values set
#
# @return [Boolean]
def has_privates?
super || userpass_file.present? || user_as_pass || !!ignore_private
super || userpass_file.present? || user_as_pass
end

end
Expand Down
37 changes: 24 additions & 13 deletions modules/auxiliary/scanner/ldap/ldap_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,9 @@ def validate_connect_options!
end

def run_host(ip)
ignore_public = datastore['LDAP::Auth'] == Msf::Exploit::Remote::AuthOption::SCHANNEL
ignore_private =
datastore['LDAP::Auth'] == Msf::Exploit::Remote::AuthOption::SCHANNEL ||
(Msf::Exploit::Remote::AuthOption::KERBEROS && !datastore['ANONYMOUS_LOGIN'] && !datastore['PASSWORD'])

cred_collection = build_credential_collection(
username: datastore['USERNAME'],
password: datastore['PASSWORD'],
realm: datastore['DOMAIN'],
anonymous_login: datastore['ANONYMOUS_LOGIN'],
blank_passwords: false,
ignore_public: ignore_public,
ignore_private: ignore_private
cred_collection = build_specific_credential_collection(
void_login: datastore['LDAP::Auth'] == Msf::Exploit::Remote::AuthOption::SCHANNEL,
no_password_login: datastore['LDAP::Auth'] == Msf::Exploit::Remote::AuthOption::KERBEROS && !datastore['ANONYMOUS_LOGIN'] && !datastore['PASSWORD']
)

opts = {
Expand Down Expand Up @@ -202,4 +192,25 @@ def session_setup(result)

start_session(self, nil, merge_me, false, my_session.rstream, my_session)
end

def build_specific_credential_collection(void_login:, no_password_login:)
if void_login
Metasploit::Framework::PrivateCredentialCollection.new({
nil_password: true
})
elsif no_password_login
Metasploit::Framework::CredentialCollection.new({
username: datastore['USERNAME'],
nil_password: true
})
else
build_credential_collection(
username: datastore['USERNAME'],
password: datastore['PASSWORD'],
realm: datastore['DOMAIN'],
anonymous_login: datastore['ANONYMOUS_LOGIN'],
blank_passwords: false
)
end
end
end
49 changes: 1 addition & 48 deletions spec/lib/metasploit/framework/credential_collection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
prepended_creds: prepended_creds,
additional_privates: additional_privates,
additional_publics: additional_publics,
password_spray: password_spray,
ignore_public: ignore_public,
ignore_private: ignore_private
password_spray: password_spray
)
end

Expand All @@ -41,8 +39,6 @@
let(:additional_privates) { [] }
let(:additional_publics) { [] }
let(:password_spray) { false }
let(:ignore_public) { nil }
let(:ignore_private) { nil }

describe "#each" do
specify do
Expand Down Expand Up @@ -596,34 +592,6 @@
)
end
end

context 'when :ignore_public is true and :username is nil' do
let(:ignore_public) { true }
let(:username) { nil }
specify do
expect { |b| collection.each(&b) }.to_not yield_control
end
end

context 'when :ignore_private is true and password is nil' do
let(:ignore_private) { true }
let(:password) { nil }
specify do
expect { |b| collection.each(&b) }.to yield_successive_args(
Metasploit::Framework::Credential.new(public: username, private: nil)
)
end

context 'when :ignore_public is also true and username is nil' do
let(:ignore_public) { true }
let(:username) { nil }
specify do
expect { |b| collection.each(&b) }.to yield_successive_args(
Metasploit::Framework::Credential.new(public: nil, private: nil)
)
end
end
end
end

describe "#empty?" do
Expand Down Expand Up @@ -693,21 +661,6 @@
expect(collection.empty?).to eq true
end
end

context "and :ignore_public is set" do
let(:ignore_public) { true }
specify do
expect(collection.empty?).to eq true
end

context "and :ignore_private is also set" do
let(:ignore_private) { true }
specify do
expect(collection.empty?).to eq false
end
end
end

end
end
end
Expand Down

0 comments on commit b08a5f6

Please sign in to comment.