From 4e9d771d646d39ab7c58b795c61fbdd6d1652d42 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 15 Nov 2024 17:47:17 +0100 Subject: [PATCH] CredentialCollection: adding various tests that currently fails to demonstrate multiple bugs in the each method --- .../framework/credential_collection_spec.rb | 263 ++++++++++++++++++ 1 file changed, 263 insertions(+) diff --git a/spec/lib/metasploit/framework/credential_collection_spec.rb b/spec/lib/metasploit/framework/credential_collection_spec.rb index 792020ac5eb0b..02278ba69ebf5 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,253 @@ 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 + 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 + + context "when :nil_passwords is true" do + let(:nil_passwords) { true } + + specify do + expect { |b| collection.each(&b) }.to yield_successive_args( + Metasploit::Framework::Credential.new(public: "asdf", private: nil), + Metasploit::Framework::Credential.new(public: "jkl", private: nil), + Metasploit::Framework::Credential.new(public: "asdf", private: password), + Metasploit::Framework::Credential.new(public: "jkl", private: password), + ) + 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