Path: blob/master/spec/lib/metasploit/framework/credential_collection_spec.rb
21962 views
require 'spec_helper'1require 'metasploit/framework/credential_collection'23RSpec.describe Metasploit::Framework::CredentialCollection do45subject(:collection) do6described_class.new(7nil_passwords: nil_passwords,8blank_passwords: blank_passwords,9pass_file: pass_file,10password: password,11user_as_pass: user_as_pass,12user_file: user_file,13username: username,14userpass_file: userpass_file,15prepended_creds: prepended_creds,16additional_privates: additional_privates,17additional_publics: additional_publics,18password_spray: password_spray19)20end2122before(:each) do23# The test suite overrides File.open(...) calls; fall back to the normal behavior for any File.open calls that aren't explicitly mocked24allow(File).to receive(:open).with(anything).and_call_original25allow(File).to receive(:open).with(anything, anything).and_call_original26allow(File).to receive(:open).with(anything, anything, anything).and_call_original27end2829let(:nil_passwords) { nil }30let(:blank_passwords) { nil }31let(:username) { "user" }32let(:password) { "pass" }33let(:user_file) { nil }34let(:pass_file) { nil }35let(:user_as_pass) { nil }36let(:userpass_file) { nil }37let(:prepended_creds) { [] }38let(:additional_privates) { [] }39let(:additional_publics) { [] }40let(:password_spray) { false }4142describe "#each" do43specify do44expect { |b| collection.each(&b) }.to yield_with_args(Metasploit::Framework::Credential)45end4647context "when given a user_file and password" do48let(:username) { nil }49let(:user_file) do50filename = "foo"51stub_file = StringIO.new("asdf\njkl\n")52allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file5354filename55end5657specify do58expect { |b| collection.each(&b) }.to yield_successive_args(59Metasploit::Framework::Credential.new(public: "asdf", private: password),60Metasploit::Framework::Credential.new(public: "jkl", private: password),61)62end63end6465context "when given a pass_file and username" do66let(:password) { nil }67let(:pass_file) do68filename = "foo"69stub_file = StringIO.new("asdf\njkl\n")70allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file7172filename73end7475specify do76expect { |b| collection.each(&b) }.to yield_successive_args(77Metasploit::Framework::Credential.new(public: username, private: "asdf"),78Metasploit::Framework::Credential.new(public: username, private: "jkl"),79)80end81end8283context "when given a userpass_file" do84let(:username) { nil }85let(:password) { nil }86let(:userpass_file) do87filename = "foo"88stub_file = StringIO.new("asdf jkl\nfoo bar\n")89allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file9091filename92end9394specify do95expect { |b| collection.each(&b) }.to yield_successive_args(96Metasploit::Framework::Credential.new(public: "asdf", private: "jkl"),97Metasploit::Framework::Credential.new(public: "foo", private: "bar"),98)99end100end101102context "when given a pass_file and user_file" do103let(:password) { nil }104let(:username) { nil }105let(:user_file) do106filename = "user_file"107stub_file = StringIO.new("asdf\njkl\n")108allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file109110filename111end112let(:pass_file) do113filename = "pass_file"114stub_file = StringIO.new("asdf\njkl\n")115allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file116117filename118end119120specify do121expect { |b| collection.each(&b) }.to yield_successive_args(122Metasploit::Framework::Credential.new(public: "asdf", private: "asdf"),123Metasploit::Framework::Credential.new(public: "asdf", private: "jkl"),124Metasploit::Framework::Credential.new(public: "jkl", private: "asdf"),125Metasploit::Framework::Credential.new(public: "jkl", private: "jkl"),126)127end128end129130context "when given a pass_file and user_file and password spray" do131let(:password) { nil }132let(:username) { nil }133let(:password_spray) { true }134let(:pass_file) do135filename = "pass_file"136stub_file = StringIO.new("password1\npassword2\n")137allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file138139filename140end141let(:user_file) do142filename = "user_file"143stub_file = StringIO.new("user1\nuser2\nuser3\n")144allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file145146filename147end148149specify do150expect { |b| collection.each(&b) }.to yield_successive_args(151Metasploit::Framework::Credential.new(public: "user1", private: "password1"),152Metasploit::Framework::Credential.new(public: "user2", private: "password1"),153Metasploit::Framework::Credential.new(public: "user3", private: "password1"),154Metasploit::Framework::Credential.new(public: "user1", private: "password2"),155Metasploit::Framework::Credential.new(public: "user2", private: "password2"),156Metasploit::Framework::Credential.new(public: "user3", private: "password2"),157)158end159end160161context 'when given a pass_file and user_file and password spray and :user_as_pass is true' do162let(:password) { nil }163let(:username) { nil }164let(:password_spray) { true }165let(:pass_file) do166filename = "pass_file"167stub_file = StringIO.new("password1\npassword2\n")168allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file169170filename171end172let(:user_file) do173filename = "user_file"174stub_file = StringIO.new("user1\nuser2\nuser3\n")175allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file176177filename178end179let(:user_as_pass) { true }180181specify do182expect { |b| collection.each(&b) }.to yield_successive_args(183Metasploit::Framework::Credential.new(public: "user1", private: "user1"),184Metasploit::Framework::Credential.new(public: "user2", private: "user2"),185Metasploit::Framework::Credential.new(public: "user3", private: "user3"),186Metasploit::Framework::Credential.new(public: "user1", private: "password1"),187Metasploit::Framework::Credential.new(public: "user2", private: "password1"),188Metasploit::Framework::Credential.new(public: "user3", private: "password1"),189Metasploit::Framework::Credential.new(public: "user1", private: "password2"),190Metasploit::Framework::Credential.new(public: "user2", private: "password2"),191Metasploit::Framework::Credential.new(public: "user3", private: "password2"),192)193end194end195196context 'when given a username and password' do197let(:password) { 'password' }198let(:username) { 'root' }199200specify do201expected = [202Metasploit::Framework::Credential.new(public: 'root', private: 'password'),203]204expect { |b| collection.each(&b) }.to yield_successive_args(*expected)205end206end207208context 'when given a pass_file, user_file, password spray and a default username' do209let(:password) { nil }210let(:username) { 'root' }211let(:password_spray) { true }212let(:pass_file) do213filename = "pass_file"214stub_file = StringIO.new("password1\npassword2\n")215allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file216217filename218end219let(:user_file) do220filename = "user_file"221stub_file = StringIO.new("user1\nuser2\nuser3\n")222allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file223224filename225end226227specify do228expected = [229Metasploit::Framework::Credential.new(public: "root", private: "password1"),230Metasploit::Framework::Credential.new(public: "user1", private: "password1"),231Metasploit::Framework::Credential.new(public: "user2", private: "password1"),232Metasploit::Framework::Credential.new(public: "user3", private: "password1"),233Metasploit::Framework::Credential.new(public: "root", private: "password2"),234Metasploit::Framework::Credential.new(public: "user1", private: "password2"),235Metasploit::Framework::Credential.new(public: "user2", private: "password2"),236Metasploit::Framework::Credential.new(public: "user3", private: "password2"),237]238expect { |b| collection.each(&b) }.to yield_successive_args(*expected)239end240end241242context 'when given a pass_file, user_file, password spray and additional privates' do243let(:password) { nil }244let(:username) { 'root' }245let(:password_spray) { true }246let(:additional_privates) { ['foo'] }247let(:pass_file) do248filename = "pass_file"249stub_file = StringIO.new("password1\npassword2\n")250allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file251252filename253end254let(:user_file) do255filename = "user_file"256stub_file = StringIO.new("user1\nuser2\nuser3\n")257allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file258259filename260end261262specify do263expected = [264Metasploit::Framework::Credential.new(public: "root", private: "password1"),265Metasploit::Framework::Credential.new(public: "user1", private: "password1"),266Metasploit::Framework::Credential.new(public: "user2", private: "password1"),267Metasploit::Framework::Credential.new(public: "user3", private: "password1"),268Metasploit::Framework::Credential.new(public: "root", private: "password2"),269Metasploit::Framework::Credential.new(public: "user1", private: "password2"),270Metasploit::Framework::Credential.new(public: "user2", private: "password2"),271Metasploit::Framework::Credential.new(public: "user3", private: "password2"),272Metasploit::Framework::Credential.new(public: "root", private: "foo"),273Metasploit::Framework::Credential.new(public: "user1", private: "foo"),274Metasploit::Framework::Credential.new(public: "user2", private: "foo"),275Metasploit::Framework::Credential.new(public: "user3", private: "foo"),276]277expect { |b| collection.each(&b) }.to yield_successive_args(*expected)278end279end280281context 'when given a username, user_file and pass_file' do282let(:password) { nil }283let(:username) { 'my_username' }284let(:user_file) do285filename = "user_file"286stub_file = StringIO.new("asdf\njkl\n")287allow(File).to receive(:open).with(filename, /^r/).and_yield stub_file288289filename290end291292let(:pass_file) do293filename = "pass_file"294stub_file = StringIO.new("asdf\njkl\n")295allow(File).to receive(:open).with(filename, /^r/).and_yield stub_file296297filename298end299300it do301expect { |b| collection.each(&b) }.to yield_successive_args(302Metasploit::Framework::Credential.new(public: "my_username", private: "asdf"),303Metasploit::Framework::Credential.new(public: "my_username", private: "jkl"),304Metasploit::Framework::Credential.new(public: "asdf", private: "asdf"),305Metasploit::Framework::Credential.new(public: "asdf", private: "jkl"),306Metasploit::Framework::Credential.new(public: "jkl", private: "asdf"),307Metasploit::Framework::Credential.new(public: "jkl", private: "jkl")308)309end310end311312context "when :user_as_pass is true" do313let(:user_as_pass) { true }314specify do315expect { |b| collection.each(&b) }.to yield_successive_args(316Metasploit::Framework::Credential.new(public: username, private: password),317Metasploit::Framework::Credential.new(public: username, private: username),318)319end320end321322context "when :nil_passwords is true" do323let(:nil_passwords) { true }324specify do325expect { |b| collection.each(&b) }.to yield_successive_args(326Metasploit::Framework::Credential.new(public: username, private: nil),327Metasploit::Framework::Credential.new(public: username, private: password),328)329end330end331332context "when using password spraying and :nil_passwords is true" do333let(:password_spray) { true }334let(:nil_passwords) { true }335336context "without password" do337let(:password) { nil }338specify do339expect { |b| collection.each(&b) }.to yield_successive_args(340Metasploit::Framework::Credential.new(public: username, private: nil)341)342end343end344end345346context "when :blank_passwords is true" do347let(:blank_passwords) { true }348specify do349expect { |b| collection.each(&b) }.to yield_successive_args(350Metasploit::Framework::Credential.new(public: username, private: password),351Metasploit::Framework::Credential.new(public: username, private: ""),352)353end354end355356context "when given additional_publics and :user_as_pass is true" do357let(:username) { nil }358let(:password) { nil }359let(:additional_publics) { [ "test_public" ] }360let(:user_as_pass) { true }361362specify do363expect { |b| collection.each(&b) }.to yield_successive_args(364Metasploit::Framework::Credential.new(public: "test_public", private: "test_public")365)366end367end368369context "when given additional_publics, :user_as_pass is true and using password spraying" do370let(:username) { nil }371let(:password) { nil }372let(:additional_publics) { [ "test_public" ] }373let(:user_as_pass) { true }374let(:password_spray) { true }375376specify do377expect { |b| collection.each(&b) }.to yield_successive_args(378Metasploit::Framework::Credential.new(public: "test_public", private: "test_public")379)380end381end382383context "when given additional_publics and :nil_password is true" do384let(:username) { nil }385let(:password) { nil }386let(:additional_publics) { [ "test_public" ] }387let(:nil_passwords) { true }388389specify do390expect { |b| collection.each(&b) }.to yield_successive_args(391Metasploit::Framework::Credential.new(public: "test_public", private: nil)392)393end394end395396context "when given additional_publics, :nil_password is true, :blank_passwords is true and using password spraying" do397let(:username) { nil }398let(:password) { nil }399let(:additional_publics) { [ "test_public1", "test_public2" ] }400let(:nil_passwords) { true }401let(:blank_passwords) { true }402let(:password_spray) { true }403404specify do405expect { |b| collection.each(&b) }.to yield_successive_args(406Metasploit::Framework::Credential.new(public: "test_public1", private: nil),407Metasploit::Framework::Credential.new(public: "test_public2", private: nil),408Metasploit::Framework::Credential.new(public: "test_public1", private: ""),409Metasploit::Framework::Credential.new(public: "test_public2", private: "")410)411end412end413414context "when given additional_publics, a user_file, a password and using password spraying" do415let(:username) { nil }416let(:password) { "password" }417let(:additional_publics) { [ "test_public" ] }418let(:user_file) do419filename = "user_file"420stub_file = StringIO.new("asdf\njkl\n")421allow(File).to receive(:open).with(filename, /^r/).and_yield stub_file422423filename424end425426specify do427expect { |b| collection.each(&b) }.to yield_successive_args(428Metasploit::Framework::Credential.new(public: "asdf", private: "password"),429Metasploit::Framework::Credential.new(public: "jkl", private: "password"),430Metasploit::Framework::Credential.new(public: "test_public", private: "password")431)432end433end434435context "when using password spraying with blank_passwords and a password (but no username)" do436let(:password_spray) { true }437let(:blank_passwords) { true }438let(:username) { nil }439let(:password) { "pass" }440441specify do442expect { |b| collection.each(&b) }.to yield_successive_args()443end444end445446context "when using password spraying with blank_passwords and a username (but no password)" do447let(:password_spray) { true }448let(:blank_passwords) { true }449let(:username) { "user" }450let(:password) { nil }451452specify do453expect { |b| collection.each(&b) }.to yield_successive_args(454Metasploit::Framework::Credential.new(public: username, private: '')455)456end457end458459context "when using password spraying with blank_passwords and given a user_file" do460let(:password_spray) { true }461let(:blank_passwords) { true }462let(:username) { nil }463let(:password) { nil }464let(:user_file) do465filename = "foo"466stub_file = StringIO.new("asdf\njkl\n")467allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file468469filename470end471472specify do473expect { |b| collection.each(&b) }.to yield_successive_args(474Metasploit::Framework::Credential.new(public: "asdf", private: ''),475Metasploit::Framework::Credential.new(public: "jkl", private: '')476)477end478end479480context "when every possible option is used" do481let(:nil_passwords) { true }482let(:blank_passwords) { true }483let(:username) { "user" }484let(:password) { "pass" }485let(:user_file) do486filename = "user_file"487stub_file = StringIO.new("userfile")488allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file489490filename491end492let(:pass_file) do493filename = "pass_file"494stub_file = StringIO.new("passfile\n")495allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file496497filename498end499let(:user_as_pass) { true }500let(:userpass_file) do501filename = "userpass_file"502stub_file = StringIO.new("userpass_user userpass_pass\n")503allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file504505filename506end507let(:prepended_creds) { ['test_prepend'] }508let(:additional_privates) { ['test_private'] }509let(:additional_publics) { ['test_public'] }510511specify do512expect { |b| collection.each(&b) }.to yield_successive_args(513"test_prepend",514Metasploit::Framework::Credential.new(public: "user", private: nil),515Metasploit::Framework::Credential.new(public: "user", private: "pass"),516Metasploit::Framework::Credential.new(public: "user", private: "user"),517Metasploit::Framework::Credential.new(public: "user", private: ""),518Metasploit::Framework::Credential.new(public: "user", private: "passfile"),519Metasploit::Framework::Credential.new(public: "user", private: "test_private"),520Metasploit::Framework::Credential.new(public: "userfile", private: nil),521Metasploit::Framework::Credential.new(public: "userfile", private: "pass"),522Metasploit::Framework::Credential.new(public: "userfile", private: "userfile"),523Metasploit::Framework::Credential.new(public: "userfile", private: ""),524Metasploit::Framework::Credential.new(public: "userfile", private: "passfile"),525Metasploit::Framework::Credential.new(public: "userfile", private: "test_private"),526Metasploit::Framework::Credential.new(public: "userpass_user", private: "userpass_pass"),527Metasploit::Framework::Credential.new(public: "test_public", private: nil), # missing this case528Metasploit::Framework::Credential.new(public: "test_public", private: "pass"),529Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"),530Metasploit::Framework::Credential.new(public: "test_public", private: ""),531Metasploit::Framework::Credential.new(public: "test_public", private: "passfile"),532Metasploit::Framework::Credential.new(public: "test_public", private: "test_private")533)534end535end536537context "when using password spraying in combination with every other option" do538let(:password_spray) { true }539let(:nil_passwords) { true }540let(:blank_passwords) { true }541let(:username) { "user" }542let(:password) { "pass" }543let(:user_file) do544filename = "user_file"545stub_file = StringIO.new("userfile")546allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file547548filename549end550let(:pass_file) do551filename = "pass_file"552stub_file = StringIO.new("passfile\n")553allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file554555filename556end557let(:user_as_pass) { true }558let(:userpass_file) do559filename = "userpass_file"560stub_file = StringIO.new("userpass_user userpass_pass\n")561allow(File).to receive(:open).with(filename,/^r/).and_yield stub_file562563filename564end565let(:prepended_creds) { ['test_prepend'] }566let(:additional_privates) { ['test_private'] }567let(:additional_publics) { ['test_public'] }568569specify do570expect { |b| collection.each(&b) }.to yield_successive_args(571"test_prepend",572Metasploit::Framework::Credential.new(public: "user", private: nil),573Metasploit::Framework::Credential.new(public: "userfile", private: nil),574Metasploit::Framework::Credential.new(public: "test_public", private: nil),575Metasploit::Framework::Credential.new(public: "user", private: "pass"),576Metasploit::Framework::Credential.new(public: "userfile", private: "pass"),577Metasploit::Framework::Credential.new(public: "test_public", private: "pass"),578Metasploit::Framework::Credential.new(public: "user", private: "user"),579Metasploit::Framework::Credential.new(public: "userfile", private: "userfile"),580Metasploit::Framework::Credential.new(public: "test_public", private: "test_public"),581Metasploit::Framework::Credential.new(public: "user", private: ""),582Metasploit::Framework::Credential.new(public: "userfile", private: ""),583Metasploit::Framework::Credential.new(public: "test_public", private: ""),584Metasploit::Framework::Credential.new(public: "user", private: "passfile"),585Metasploit::Framework::Credential.new(public: "userfile", private: "passfile"),586Metasploit::Framework::Credential.new(public: "test_public", private: "passfile"),587Metasploit::Framework::Credential.new(public: "userpass_user", private: "userpass_pass"),588Metasploit::Framework::Credential.new(public: "user", private: "test_private"),589Metasploit::Framework::Credential.new(public: "userfile", private: "test_private"),590Metasploit::Framework::Credential.new(public: "test_public", private: "test_private")591)592end593end594end595596describe "#empty?" do597context "when only :userpass_file is set" do598let(:username) { nil }599let(:password) { nil }600let(:userpass_file) { "test_file" }601specify do602expect(collection.empty?).to eq false603end604end605606context "when :username is set" do607context "and :password is set" do608specify do609expect(collection.empty?).to eq false610end611end612613context "and :password is not set" do614let(:password) { nil }615specify do616expect(collection.empty?).to eq true617end618619context "and :nil_passwords is true" do620let(:nil_passwords) { true }621specify do622expect(collection.empty?).to eq false623end624end625626context "and :blank_passwords is true" do627let(:blank_passwords) { true }628specify do629expect(collection.empty?).to eq false630end631end632end633end634635context "when :username is not set" do636context "and :password is not set" do637let(:username) { nil }638let(:password) { nil }639specify do640expect(collection.empty?).to eq true641end642643context "and :prepended_creds is not empty" do644let(:prepended_creds) { [ "test" ] }645specify do646expect(collection.empty?).to eq false647end648end649650context "and :additional_privates is not empty" do651let(:additional_privates) { [ "test_private" ] }652specify do653expect(collection.empty?).to eq true654end655end656657context "and :additional_publics is not empty" do658let(:additional_publics) { [ "test_public" ] }659specify do660expect(collection.empty?).to eq true661end662end663end664end665end666667describe "#prepend_cred" do668specify do669prep = Metasploit::Framework::Credential.new(public: "foo", private: "bar")670collection.prepend_cred(prep)671expect { |b| collection.each(&b) }.to yield_successive_args(672prep,673Metasploit::Framework::Credential.new(public: username, private: password),674)675end676end677678end679680681