diff --git a/lib/metasploit/framework/credential_collection.rb b/lib/metasploit/framework/credential_collection.rb index 11e8a4f81867..de9135b93234 100644 --- a/lib/metasploit/framework/credential_collection.rb +++ b/lib/metasploit/framework/credential_collection.rb @@ -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} @@ -257,29 +240,29 @@ def add_public(public_str='') # @yieldparam credential [Metasploit::Framework::Credential] # @return [void] def each_filtered - 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 - elsif password_spray - each_unfiltered_password_first do |credential| - next unless self.filter.nil? || self.filter.call(credential) - - yield credential - end - else - each_unfiltered_username_first do |credential| - next unless self.filter.nil? || self.filter.call(credential) + each_unfiltered do |credential| + next unless self.filter.nil? || self.filter.call(credential) - yield credential - end + yield credential end end alias each each_filtered + def each_unfiltered(&block) + prepended_creds.each { |c| yield c } + + if anonymous_login + yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password) + end + + if password_spray + each_unfiltered_password_first(&block) + else + each_unfiltered_username_first(&block) + end + end + # When password spraying is enabled, do first passwords then usernames # i.e. # username1:password1 @@ -293,117 +276,72 @@ def each_filtered # @yieldparam credential [Metasploit::Framework::Credential] # @return [void] def each_unfiltered_password_first - if user_file.present? - user_fd = File.open(user_file, 'r:binary') - end - - prepended_creds.each { |c| yield c } - - if anonymous_login - yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password) - end - - if user_as_pass - if user_fd - user_fd.each_line do |user_from_file| - user_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm, private_type: private_type(password)) - end - user_fd.seek(0) + if nil_passwords + each_username do |username| + yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password) end end if password.present? - if nil_passwords - yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password) - end - if username.present? + each_username do |username| yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password)) end - if user_as_pass + end + + if user_as_pass + each_username do |username| yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password) end - if blank_passwords + end + + if blank_passwords + each_username do |username| yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password) end - if user_fd - user_fd.each_line do |user_from_file| - user_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password)) - end - user_fd.seek(0) - end end if pass_file.present? File.open(pass_file, 'r:binary') do |pass_fd| pass_fd.each_line do |pass_from_file| pass_from_file.chomp! - if username.present? - yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: :password) - end - next unless user_fd - user_fd.each_line do |user_from_file| - user_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) + each_username do |username| + yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) end - user_fd.seek(0) end end end - if userpass_file.present? - File.open(userpass_file, 'r:binary') do |userpass_fd| - userpass_fd.each_line do |line| - user, pass = line.split(" ", 2) - if pass.blank? - pass = '' - else - pass.chomp! - end - yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm) - end - end + each_user_pass_from_userpass_file do |user, pass| + yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm) end additional_privates.each do |add_private| - if username.present? + each_username do |username| yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private)) end - user_fd.each_line do |user_from_file| - user_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private)) - end - user_fd.seek(0) end + end - additional_publics.each do |add_public| - if password.present? - yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) ) - end - if user_as_pass - yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password) - end - if blank_passwords - yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password) - end - if nil_passwords - yield Metasploit::Framework::Credential.new(public: add_public, private: nil, realm: realm, private_type: :password) - end - if user_fd + # Iterates over all possible usernames + def each_username + if username.present? + yield username + end + + if user_file.present? + File.open(user_file, 'r:binary') do |user_fd| user_fd.each_line do |user_from_file| user_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: private_type(user_from_file)) + yield user_from_file end user_fd.seek(0) end - additional_privates.each do |add_private| - yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private)) - end end - ensure - user_fd.close if user_fd && !user_fd.closed? + + additional_publics.each do |add_public| + yield add_public + end end # When password spraying is not enabled, do first usernames then passwords @@ -418,38 +356,9 @@ def each_unfiltered_password_first # @yieldparam credential [Metasploit::Framework::Credential] # @return [void] def each_unfiltered_username_first - if pass_file.present? - pass_fd = File.open(pass_file, 'r:binary') - end - - prepended_creds.each { |c| yield c } - - if anonymous_login - yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password) - end - if username.present? - if nil_passwords - yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password) - end - if password.present? - yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password)) - end - if user_as_pass - yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password) - end - if blank_passwords - yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password) - end - if pass_fd - pass_fd.each_line do |pass_from_file| - pass_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) - end - pass_fd.seek(0) - end - additional_privates.each do |add_private| - yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private)) + each_password(username) do |password, private_type| + yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type) end end @@ -457,69 +366,69 @@ def each_unfiltered_username_first File.open(user_file, 'r:binary') do |user_fd| user_fd.each_line do |user_from_file| user_from_file.chomp! - if nil_passwords - yield Metasploit::Framework::Credential.new(public: user_from_file, private: nil, realm: realm, private_type: :password) - end - if password.present? - yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password) ) - end - if user_as_pass - yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm, private_type: :password) - end - if blank_passwords - yield Metasploit::Framework::Credential.new(public: user_from_file, private: "", realm: realm, private_type: :password) - end - if pass_fd - pass_fd.each_line do |pass_from_file| - pass_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) - end - pass_fd.seek(0) - end - additional_privates.each do |add_private| - yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private)) + each_password(user_from_file) do |password, private_type| + yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type) end end end end - if userpass_file.present? - File.open(userpass_file, 'r:binary') do |userpass_fd| - userpass_fd.each_line do |line| - user, pass = line.split(" ", 2) - if pass.blank? - pass = '' - else - pass.chomp! - end - yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm) - end - end + each_user_pass_from_userpass_file do |user, pass| + yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm) end additional_publics.each do |add_public| - if password.present? - yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) ) + each_password(add_public) do |password, private_type| + yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type) end - if user_as_pass - yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password) - end - if blank_passwords - yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password) - end - if pass_fd + end + end + + # Iterates over all possible passwords + def each_password(user) + if nil_passwords + yield [nil, :password] + end + + if password.present? + yield [password, private_type(password)] + end + + if user_as_pass + yield [user, :password] + end + + if blank_passwords + yield ["", :password] + end + + if pass_file + File.open(pass_file, 'r:binary') do |pass_fd| pass_fd.each_line do |pass_from_file| pass_from_file.chomp! - yield Metasploit::Framework::Credential.new(public: add_public, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) + yield [pass_from_file, private_type(pass_from_file)] end pass_fd.seek(0) end - additional_privates.each do |add_private| - yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private)) + end + + additional_privates.each do |add_private| + yield [add_private, private_type(add_private)] + end + end + + # Iterates on userpass file if present + def each_user_pass_from_userpass_file + return unless userpass_file.present? + + File.open(userpass_file, 'r:binary') do |userpass_fd| + userpass_fd.each_line do |line| + user, pass = line.split(" ", 2) + pass = pass.blank? ? '' : pass.chomp! + + yield [user, pass] end end - ensure - pass_fd.close if pass_fd && !pass_fd.closed? end # Returns true when #each will have no results to iterate @@ -533,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 diff --git a/modules/auxiliary/scanner/ldap/ldap_login.rb b/modules/auxiliary/scanner/ldap/ldap_login.rb index 47c6dac14db9..76a17e1a4372 100644 --- a/modules/auxiliary/scanner/ldap/ldap_login.rb +++ b/modules/auxiliary/scanner/ldap/ldap_login.rb @@ -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 = { @@ -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 diff --git a/spec/lib/metasploit/framework/credential_collection_spec.rb b/spec/lib/metasploit/framework/credential_collection_spec.rb index 3fd679966d6f..a4d3cc365012 100644 --- a/spec/lib/metasploit/framework/credential_collection_spec.rb +++ b/spec/lib/metasploit/framework/credential_collection_spec.rb @@ -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 @@ -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 @@ -72,7 +68,7 @@ let(:pass_file) do filename = "foo" stub_file = StringIO.new("asdf\njkl\n") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file filename end @@ -85,7 +81,7 @@ end end - context "when given a userspass_file" do + context "when given a userpass_file" do let(:username) { nil } let(:password) { nil } let(:userpass_file) do @@ -117,7 +113,7 @@ let(:pass_file) do filename = "pass_file" stub_file = StringIO.new("asdf\njkl\n") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file filename end @@ -146,7 +142,7 @@ let(:user_file) do filename = "user_file" stub_file = StringIO.new("user1\nuser2\nuser3\n") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file filename end @@ -161,23 +157,40 @@ Metasploit::Framework::Credential.new(public: "user3", private: "password2"), ) end + end - context 'when :user_as_pass is true' do - let(:user_as_pass) { true } + context 'when given a pass_file and user_file and password spray and :user_as_pass is true' do + let(:password) { nil } + let(:username) { nil } + let(:password_spray) { true } + let(:pass_file) do + filename = "pass_file" + stub_file = StringIO.new("password1\npassword2\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file - specify do - expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: "user1", private: "user1"), - Metasploit::Framework::Credential.new(public: "user2", private: "user2"), - Metasploit::Framework::Credential.new(public: "user3", private: "user3"), - Metasploit::Framework::Credential.new(public: "user1", private: "password1"), - Metasploit::Framework::Credential.new(public: "user2", private: "password1"), - Metasploit::Framework::Credential.new(public: "user3", private: "password1"), - Metasploit::Framework::Credential.new(public: "user1", private: "password2"), - Metasploit::Framework::Credential.new(public: "user2", private: "password2"), - Metasploit::Framework::Credential.new(public: "user3", private: "password2"), - ) - end + filename + end + let(:user_file) do + filename = "user_file" + stub_file = StringIO.new("user1\nuser2\nuser3\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:user_as_pass) { true } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "user1", private: "user1"), + Metasploit::Framework::Credential.new(public: "user2", private: "user2"), + Metasploit::Framework::Credential.new(public: "user3", private: "user3"), + Metasploit::Framework::Credential.new(public: "user1", private: "password1"), + Metasploit::Framework::Credential.new(public: "user2", private: "password1"), + Metasploit::Framework::Credential.new(public: "user3", private: "password1"), + Metasploit::Framework::Credential.new(public: "user1", private: "password2"), + Metasploit::Framework::Credential.new(public: "user2", private: "password2"), + Metasploit::Framework::Credential.new(public: "user3", private: "password2"), + ) end end @@ -207,7 +220,7 @@ let(:user_file) do filename = "user_file" stub_file = StringIO.new("user1\nuser2\nuser3\n") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file filename end @@ -242,7 +255,7 @@ let(:user_file) do filename = "user_file" stub_file = StringIO.new("user1\nuser2\nuser3\n") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file filename end @@ -280,7 +293,7 @@ let(:pass_file) do filename = "pass_file" stub_file = StringIO.new("asdf\njkl\n") - allow(File).to receive(:open).with(filename, /^r/).and_return stub_file + allow(File).to receive(:open).with(filename, /^r/).and_yield stub_file filename end @@ -317,6 +330,20 @@ end end + context "when using password spraying and :nil_passwords is true" do + let(:password_spray) { true } + let(:nil_passwords) { true } + + context "without password" do + let(:password) { nil } + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: username, private: nil) + ) + end + end + end + context "when :blank_passwords is true" do let(:blank_passwords) { true } specify do @@ -327,34 +354,244 @@ end end - context 'when :ignore_public is true and :username is nil' do - let(:ignore_public) { true } + context "when given additional_publics and :user_as_pass is true" do let(:username) { nil } - specify do - expect { |b| collection.each(&b) }.to_not yield_control + let(:password) { nil } + let(:additional_publics) { [ "test_public" ] } + let(:user_as_pass) { true } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public", private: "test_public") + ) end end - context 'when :ignore_private is true and password is nil' do - let(:ignore_private) { true } + context "when given additional_publics, :user_as_pass is true and using password spraying" do + let(:username) { nil } let(:password) { nil } - specify do + let(:additional_publics) { [ "test_public" ] } + let(:user_as_pass) { true } + let(:password_spray) { true } + + specify do expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: username, private: nil) + Metasploit::Framework::Credential.new(public: "test_public", private: "test_public") ) end + 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 + context "when given additional_publics and :nil_password is true" do + let(:username) { nil } + let(:password) { nil } + let(:additional_publics) { [ "test_public" ] } + let(:nil_passwords) { true } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public", private: nil) + ) + end + end + + context "when given additional_publics, :nil_password is true, :blank_passwords is true and using password spraying" do + let(:username) { nil } + let(:password) { nil } + let(:additional_publics) { [ "test_public1", "test_public2" ] } + let(:nil_passwords) { true } + let(:blank_passwords) { true } + let(:password_spray) { true } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public1", private: nil), + Metasploit::Framework::Credential.new(public: "test_public2", private: nil), + Metasploit::Framework::Credential.new(public: "test_public1", private: ""), + Metasploit::Framework::Credential.new(public: "test_public2", private: "") + ) + end + end + + context "when given additional_publics, a user_file, a password and using password spraying" do + let(:username) { nil } + let(:password) { "password" } + let(:additional_publics) { [ "test_public" ] } + let(:user_file) do + filename = "user_file" + stub_file = StringIO.new("asdf\njkl\n") + allow(File).to receive(:open).with(filename, /^r/).and_yield stub_file + + filename + end + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "asdf", private: "password"), + Metasploit::Framework::Credential.new(public: "jkl", private: "password"), + Metasploit::Framework::Credential.new(public: "test_public", private: "password") + ) + end + end + + context "when using password spraying with blank_passwords and a password (but no username)" do + let(:password_spray) { true } + let(:blank_passwords) { true } + let(:username) { nil } + let(:password) { "pass" } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args() + end + end + + context "when using password spraying with blank_passwords and a username (but no password)" do + let(:password_spray) { true } + let(:blank_passwords) { true } + let(:username) { "user" } + let(:password) { nil } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: username, private: '') + ) + end + end + + context "when using password spraying with blank_passwords and given a user_file" do + let(:password_spray) { true } + let(:blank_passwords) { true } + let(:username) { nil } + let(:password) { nil } + let(:user_file) do + filename = "foo" + stub_file = StringIO.new("asdf\njkl\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "asdf", private: ''), + Metasploit::Framework::Credential.new(public: "jkl", private: '') + ) end end + context "when every possible option is used" do + let(:nil_passwords) { true } + let(:blank_passwords) { true } + let(:username) { "user" } + let(:password) { "pass" } + let(:user_file) do + filename = "user_file" + stub_file = StringIO.new("userfile") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:pass_file) do + filename = "pass_file" + stub_file = StringIO.new("passfile\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:user_as_pass) { true } + let(:userpass_file) do + filename = "userpass_file" + stub_file = StringIO.new("userpass_user userpass_pass\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:prepended_creds) { ['test_prepend'] } + let(:additional_privates) { ['test_private'] } + let(:additional_publics) { ['test_public'] } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + "test_prepend", + Metasploit::Framework::Credential.new(public: "user", private: nil), + Metasploit::Framework::Credential.new(public: "user", private: "pass"), + Metasploit::Framework::Credential.new(public: "user", private: "user"), + Metasploit::Framework::Credential.new(public: "user", private: ""), + Metasploit::Framework::Credential.new(public: "user", private: "passfile"), + Metasploit::Framework::Credential.new(public: "user", private: "test_private"), + Metasploit::Framework::Credential.new(public: "userfile", private: nil), + Metasploit::Framework::Credential.new(public: "userfile", private: "pass"), + Metasploit::Framework::Credential.new(public: "userfile", private: "userfile"), + Metasploit::Framework::Credential.new(public: "userfile", private: ""), + Metasploit::Framework::Credential.new(public: "userfile", private: "passfile"), + Metasploit::Framework::Credential.new(public: "userfile", private: "test_private"), + Metasploit::Framework::Credential.new(public: "userpass_user", private: "userpass_pass"), + Metasploit::Framework::Credential.new(public: "test_public", private: nil), # missing this case + Metasploit::Framework::Credential.new(public: "test_public", private: "pass"), + Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"), + Metasploit::Framework::Credential.new(public: "test_public", private: ""), + Metasploit::Framework::Credential.new(public: "test_public", private: "passfile"), + Metasploit::Framework::Credential.new(public: "test_public", private: "test_private") + ) + end + end + + context "when using password spraying in combination with every other option" do + let(:password_spray) { true } + let(:nil_passwords) { true } + let(:blank_passwords) { true } + let(:username) { "user" } + let(:password) { "pass" } + let(:user_file) do + filename = "user_file" + stub_file = StringIO.new("userfile") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:pass_file) do + filename = "pass_file" + stub_file = StringIO.new("passfile\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:user_as_pass) { true } + let(:userpass_file) do + filename = "userpass_file" + stub_file = StringIO.new("userpass_user userpass_pass\n") + allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file + + filename + end + let(:prepended_creds) { ['test_prepend'] } + let(:additional_privates) { ['test_private'] } + let(:additional_publics) { ['test_public'] } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + "test_prepend", + Metasploit::Framework::Credential.new(public: "user", private: nil), + Metasploit::Framework::Credential.new(public: "userfile", private: nil), + Metasploit::Framework::Credential.new(public: "test_public", private: nil), + Metasploit::Framework::Credential.new(public: "user", private: "pass"), + Metasploit::Framework::Credential.new(public: "userfile", private: "pass"), + Metasploit::Framework::Credential.new(public: "test_public", private: "pass"), + Metasploit::Framework::Credential.new(public: "user", private: "user"), + Metasploit::Framework::Credential.new(public: "userfile", private: "userfile"), + Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"), + Metasploit::Framework::Credential.new(public: "user", private: ""), + Metasploit::Framework::Credential.new(public: "userfile", private: ""), + Metasploit::Framework::Credential.new(public: "test_public", private: ""), + Metasploit::Framework::Credential.new(public: "user", private: "passfile"), + Metasploit::Framework::Credential.new(public: "userfile", private: "passfile"), + Metasploit::Framework::Credential.new(public: "test_public", private: "passfile"), + Metasploit::Framework::Credential.new(public: "userpass_user", private: "userpass_pass"), + Metasploit::Framework::Credential.new(public: "user", private: "test_private"), + Metasploit::Framework::Credential.new(public: "userfile", private: "test_private"), + Metasploit::Framework::Credential.new(public: "test_public", private: "test_private") + ) + end + end end describe "#empty?" do @@ -424,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