From 7cab903b02b2c952bf5182650dd70667f4a25360 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 15 Nov 2024 17:47:17 +0100 Subject: [PATCH 1/6] CredentialCollection: adding various tests that currently fails to demonstrate multiple bugs in the each method --- .../framework/credential_collection_spec.rb | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/spec/lib/metasploit/framework/credential_collection_spec.rb b/spec/lib/metasploit/framework/credential_collection_spec.rb index 792020ac5eb0..2b843f1763af 100644 --- a/spec/lib/metasploit/framework/credential_collection_spec.rb +++ b/spec/lib/metasploit/framework/credential_collection_spec.rb @@ -98,6 +98,8 @@ Metasploit::Framework::Credential.new(public: "foo", private: "bar"), ) end + + # REMOVE BEFORE COMMIT: question for the userpass file: do we want to make options work with it or not? end context "when given a pass_file and user_file" do @@ -311,6 +313,20 @@ Metasploit::Framework::Credential.new(public: username, private: password), ) end + + context "when using password spraying" do + let(:password_spray) { true } + + # REMOVE BEFORE COMMIT: yields nothings, fails because of bug in method + 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 end context "when :blank_passwords is true" do @@ -323,6 +339,240 @@ end end + context "when given additional_publics" do + let(:username) { nil } + let(:password) { nil } + let(:additional_publics) { [ "test_public" ] } + + context "when :user_as_pass is true" do + let(:user_as_pass) { true } + + # REMOVE BEFORE COMMIT currently failing + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"), + ) + end + + + context "when using password spraying" do + let(:password_spray) { true } + + # REMOVE BEFORE COMMIT currently failing + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"), + ) + end + end + end + + context "when :nil_passwords is true" do + let(:nil_passwords) { true } + + # REMOVE BEFORE COMMIT: this option is ignored currently for additional_publics + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public", private: nil), + ) + end + end + + context "when using password spraying" do + let(:password_spray) { true } + + context "when :blank_passwords and :nil_password are true" do + let(:blank_passwords) { true } + let(:nil_passwords) { true } + + context "with 2 additional_publics" do + let(:additional_publics) { [ "test_public1", "test_public2" ] } + + # REMOVE BEFORE COMMIT: fails because no pwd spraying + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public1", private: ""), + Metasploit::Framework::Credential.new(public: "test_public2", private: ""), + Metasploit::Framework::Credential.new(public: "test_public1", private: nil), + Metasploit::Framework::Credential.new(public: "test_public2", private: nil), + ) + end + end + end + + context "when given a user file" do + let(:user_file) do + filename = "user_file" + stub_file = StringIO.new("asdf\njkl\n") + allow(File).to receive(:open).with(filename, /^r/).and_return stub_file + + filename + end + + # REMOVE BEFORE COMMIT: this also yields the usernames as passwords for the additional_public + context "when given a password" do + let(:password) { "password" } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "adsf", private: "password"), + Metasploit::Framework::Credential.new(public: "jkl", private: "password"), + Metasploit::Framework::Credential.new(public: "test_public", private: "password"), + ) + end + end + end + end + end + + context "when using password spraying" do + let(:password_spray) { true } + let(:username) { nil } + let(:password) { nil } + + context "when :blank_passwords is true" do + let(:blank_passwords) { true } + + context "with password (but no username)" do + let(:password) { "pass" } + + # REMOVE BEFORE COMMIT: this yields empty creds (no username, no pass) + specify do + expect { |b| collection.each(&b) }.to yield_successive_args() + end + end + + # REMOVE BEFORE COMMIT: yields nothings, fails because of bug in method + context "with username (but no password)" do + let(:username) { "user" } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: username, private: ''), + ) + end + end + + context "when given a user_file" do + let(:user_file) do + filename = "foo" + stub_file = StringIO.new("asdf\njkl\n") + allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + + filename + end + + # REMOVE BEFORE COMMIT: yields nothing, same for blank passwords option + 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 + 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_return stub_file + + filename + end + let(:user_as_pass) { false } + 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'] } + + # REMOVE BEFORE COMMIT: fails because of the useraspass error, then fails because of the nil value for addiitonal publics and should be ok then + 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 + + context "when using password spraying" do + let(:password_spray) { true } + let(:user_file) do + filename = "user_file" + stub_file = StringIO.new("userfile") + allow(File).to receive(:open).with(filename,/^r/).and_return 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 + + 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 end describe "#empty?" do From 5d7d8cfe3688283179e840eb6e9eec822d6807a2 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Mon, 18 Nov 2024 15:38:17 +0100 Subject: [PATCH 2/6] Fixes trivial bugs when combining additional_publics with user_as_pass --- lib/metasploit/framework/credential_collection.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/metasploit/framework/credential_collection.rb b/lib/metasploit/framework/credential_collection.rb index 57f1f7726cfb..761dcea036f8 100644 --- a/lib/metasploit/framework/credential_collection.rb +++ b/lib/metasploit/framework/credential_collection.rb @@ -360,7 +360,7 @@ def each_unfiltered_password_first 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) + yield Metasploit::Framework::Credential.new(public: add_public, private: add_public, realm: realm, private_type: :password) end if blank_passwords yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password) @@ -479,7 +479,7 @@ def each_unfiltered_username_first 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) + yield Metasploit::Framework::Credential.new(public: add_public, private: add_public, realm: realm, private_type: :password) end if blank_passwords yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password) From 397f4666d8bbe7266d7a1baa811e70582a3cdf6d Mon Sep 17 00:00:00 2001 From: Mathieu Date: Mon, 18 Nov 2024 15:48:09 +0100 Subject: [PATCH 3/6] Fixes the fact that no nil credential is generated for additional_publics --- lib/metasploit/framework/credential_collection.rb | 3 +++ spec/lib/metasploit/framework/credential_collection_spec.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/metasploit/framework/credential_collection.rb b/lib/metasploit/framework/credential_collection.rb index 761dcea036f8..d640f411356a 100644 --- a/lib/metasploit/framework/credential_collection.rb +++ b/lib/metasploit/framework/credential_collection.rb @@ -475,6 +475,9 @@ def each_unfiltered_username_first end additional_publics.each do |add_public| + if nil_passwords + yield Metasploit::Framework::Credential.new(public: add_public, private: nil, realm: realm, private_type: :password) + end if password.present? yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) ) end diff --git a/spec/lib/metasploit/framework/credential_collection_spec.rb b/spec/lib/metasploit/framework/credential_collection_spec.rb index 2b843f1763af..cf1dcbae4164 100644 --- a/spec/lib/metasploit/framework/credential_collection_spec.rb +++ b/spec/lib/metasploit/framework/credential_collection_spec.rb @@ -504,7 +504,7 @@ let(:additional_privates) { ['test_private'] } let(:additional_publics) { ['test_public'] } - # REMOVE BEFORE COMMIT: fails because of the useraspass error, then fails because of the nil value for addiitonal publics and should be ok then + # REMOVE BEFORE COMMIT: fails because of the useraspass error, then fails because of the nil value for addittonal publics and should be ok then specify do expect { |b| collection.each(&b) }.to yield_successive_args( "test_prepend", From 5fce8d2bf7226825c2534c53f750863327923f97 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Mon, 18 Nov 2024 16:09:18 +0100 Subject: [PATCH 4/6] Fix incorrect expectations of currently failing tests --- .../metasploit/framework/credential_collection_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/lib/metasploit/framework/credential_collection_spec.rb b/spec/lib/metasploit/framework/credential_collection_spec.rb index cf1dcbae4164..7de4a3f2132a 100644 --- a/spec/lib/metasploit/framework/credential_collection_spec.rb +++ b/spec/lib/metasploit/framework/credential_collection_spec.rb @@ -391,10 +391,10 @@ # REMOVE BEFORE COMMIT: fails because no pwd spraying specify do expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: "test_public1", private: ""), - Metasploit::Framework::Credential.new(public: "test_public2", private: ""), 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 @@ -415,7 +415,7 @@ specify do expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: "adsf", private: "password"), + 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"), ) @@ -492,7 +492,7 @@ filename end - let(:user_as_pass) { false } + let(:user_as_pass) { true } let(:userpass_file) do filename = "userpass_file" stub_file = StringIO.new("userpass_user userpass_pass\n") From 383dc0da32c6f0fc3be8917ca5fb46456e7e0247 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Mon, 18 Nov 2024 16:11:36 +0100 Subject: [PATCH 5/6] Re-implement the each_unfiltered_password_first method (used in case of password spraying) to make all tests pass --- .../framework/credential_collection.rb | 98 ++++++++++++------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/lib/metasploit/framework/credential_collection.rb b/lib/metasploit/framework/credential_collection.rb index d640f411356a..8bab6b88053d 100644 --- a/lib/metasploit/framework/credential_collection.rb +++ b/lib/metasploit/framework/credential_collection.rb @@ -280,52 +280,98 @@ def each_unfiltered_password_first yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password) end - if user_as_pass + if nil_passwords + if username.present? + yield Metasploit::Framework::Credential.new(public: username, private: nil, 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: user_from_file, realm: realm, private_type: private_type(password)) + yield Metasploit::Framework::Credential.new(public: user_from_file, private: nil, realm: realm, private_type: :password) end user_fd.seek(0) end + + additional_publics.each do |add_public| + yield Metasploit::Framework::Credential.new(public: add_public, 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? yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: 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: password, realm: realm, private_type: private_type(password)) + end + user_fd.seek(0) + end + + additional_publics.each do |add_public| + yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password)) + end + end + + if user_as_pass + if username.present? yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password) end - if blank_passwords + + 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) + end + + additional_publics.each do |add_public| + yield Metasploit::Framework::Credential.new(public: add_public, private: add_public, realm: realm, private_type: :password) + end + end + + if blank_passwords + if username.present? 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)) + yield Metasploit::Framework::Credential.new(public: user_from_file, private: "", realm: realm, private_type: :password) end user_fd.seek(0) end + + additional_publics.each do |add_public| + yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password) + 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) + yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) + 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: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) + end + user_fd.seek(0) 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)) + additional_publics.each do |add_public| + yield Metasploit::Framework::Credential.new(public: add_public, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) end - user_fd.seek(0) end end end @@ -348,34 +394,16 @@ def each_unfiltered_password_first if username.present? 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 - 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: add_public, 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 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 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 - additional_privates.each do |add_private| + + additional_publics.each do |add_public| yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private)) end end From e03f2e2ea7b4eac85d589276d96d5f358a576621 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 13 Dec 2024 17:13:56 +0100 Subject: [PATCH 6/6] Inline all specs to avoid nesting context --- .../framework/credential_collection_spec.rb | 385 ++++++++++-------- 1 file changed, 207 insertions(+), 178 deletions(-) diff --git a/spec/lib/metasploit/framework/credential_collection_spec.rb b/spec/lib/metasploit/framework/credential_collection_spec.rb index 7de4a3f2132a..dcb16827964e 100644 --- a/spec/lib/metasploit/framework/credential_collection_spec.rb +++ b/spec/lib/metasploit/framework/credential_collection_spec.rb @@ -68,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 @@ -81,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 @@ -98,8 +98,6 @@ Metasploit::Framework::Credential.new(public: "foo", private: "bar"), ) end - - # REMOVE BEFORE COMMIT: question for the userpass file: do we want to make options work with it or not? end context "when given a pass_file and user_file" do @@ -115,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 @@ -144,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 @@ -159,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 @@ -205,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 @@ -240,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 @@ -278,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 @@ -313,18 +328,19 @@ Metasploit::Framework::Credential.new(public: username, private: password), ) end + end - context "when using password spraying" do - let(:password_spray) { true } + context "when using password spraying and :nil_passwords is true" do + let(:password_spray) { true } + let(:nil_passwords) { true } - # REMOVE BEFORE COMMIT: yields nothings, fails because of bug in method - 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 + # REMOVE BEFORE COMMIT: yields nothings, fails because of bug in method + 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 @@ -339,137 +355,135 @@ end end - context "when given additional_publics" do + context "when given additional_publics and :user_as_pass is true" do let(:username) { nil } let(:password) { nil } let(:additional_publics) { [ "test_public" ] } + let(:user_as_pass) { true } - context "when :user_as_pass is true" do - let(:user_as_pass) { true } - - # REMOVE BEFORE COMMIT currently failing - specify do - expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"), - ) - end - + # REMOVE BEFORE COMMIT currently failing + 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 using password spraying" do - let(:password_spray) { true } + context "when given additional_publics, :user_as_pass is true and using password spraying" do + let(:username) { nil } + let(:password) { nil } + let(:additional_publics) { [ "test_public" ] } + let(:user_as_pass) { true } + let(:password_spray) { true } - # REMOVE BEFORE COMMIT currently failing - specify do - expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"), - ) - end - end + # REMOVE BEFORE COMMIT currently failing + 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 :nil_passwords is true" do - let(:nil_passwords) { true } + 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 } - # REMOVE BEFORE COMMIT: this option is ignored currently for additional_publics - specify do - expect { |b| collection.each(&b) }.to yield_successive_args( - Metasploit::Framework::Credential.new(public: "test_public", private: nil), - ) - end + # REMOVE BEFORE COMMIT: this option is ignored currently for additional_publics + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "test_public", private: nil), + ) end + end - context "when using password spraying" do - let(:password_spray) { true } - - context "when :blank_passwords and :nil_password are true" do - let(:blank_passwords) { true } - let(:nil_passwords) { true } + 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 } - context "with 2 additional_publics" do - let(:additional_publics) { [ "test_public1", "test_public2" ] } - - # REMOVE BEFORE COMMIT: fails because no pwd spraying - 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 - end + # REMOVE BEFORE COMMIT: fails because no pwd spraying + 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 a user file" do - let(:user_file) do - filename = "user_file" - stub_file = StringIO.new("asdf\njkl\n") - allow(File).to receive(:open).with(filename, /^r/).and_return stub_file + 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 + filename + end - # REMOVE BEFORE COMMIT: this also yields the usernames as passwords for the additional_public - context "when given a password" do - let(:password) { "password" } - - 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 - end + # REMOVE BEFORE COMMIT: this also yields the usernames as passwords for the additional_public + 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" do + 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) { nil } - - context "when :blank_passwords is true" do - let(:blank_passwords) { true } - - context "with password (but no username)" do - let(:password) { "pass" } + let(:password) { "pass" } - # REMOVE BEFORE COMMIT: this yields empty creds (no username, no pass) - specify do - expect { |b| collection.each(&b) }.to yield_successive_args() - end - end + # REMOVE BEFORE COMMIT: this yields empty creds (no username, no pass) + specify do + expect { |b| collection.each(&b) }.to yield_successive_args() + end + end - # REMOVE BEFORE COMMIT: yields nothings, fails because of bug in method - context "with username (but no password)" do - let(:username) { "user" } + 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 + # REMOVE BEFORE COMMIT: this yields empty creds (no username, no pass) + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: username, private: ''), + ) + end + end - context "when given a user_file" do - let(:user_file) do - filename = "foo" - stub_file = StringIO.new("asdf\njkl\n") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + 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 + filename + end - # REMOVE BEFORE COMMIT: yields nothing, same for blank passwords option - 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 + # REMOVE BEFORE COMMIT: yields nothing, same for blank passwords option + 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 @@ -488,7 +502,7 @@ let(:pass_file) do filename = "pass_file" stub_file = StringIO.new("passfile\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 @@ -529,48 +543,63 @@ Metasploit::Framework::Credential.new(public: "test_public", private: "test_private") ) end + end - context "when using password spraying" do - let(:password_spray) { true } - let(:user_file) do - filename = "user_file" - stub_file = StringIO.new("userfile") - allow(File).to receive(:open).with(filename,/^r/).and_return stub_file + 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(: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 + 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 - 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 + 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