292 lines
9.5 KiB
Ruby
292 lines
9.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
describe WPScan::Controller::Core do
|
|
subject(:core) { described_class.new }
|
|
let(:target_url) { 'http://ex.lo/' }
|
|
let(:cli_args) { "--url #{target_url}" }
|
|
|
|
before do
|
|
described_class.reset
|
|
WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
|
|
end
|
|
|
|
describe '#cli_options' do
|
|
its(:cli_options) { should_not be_empty }
|
|
its(:cli_options) { should be_a Array }
|
|
|
|
it 'contains to correct options' do
|
|
cli_options = core.cli_options
|
|
expect(cli_options.map(&:to_sym)).to include(:url, :server, :force, :update)
|
|
|
|
# Ensures the :url is the first one and is correctly setup
|
|
expect(cli_options.first.to_sym).to eql :url
|
|
expect(cli_options.first.required_unless).to match_array %i[update help hh version]
|
|
end
|
|
end
|
|
|
|
describe '#load_server_module' do
|
|
after do
|
|
expect(core.target).to receive(:server).and_return(@stubbed_server)
|
|
expect(core.load_server_module).to eql @expected
|
|
|
|
[core.target, WPScan::Model::WpItem.new(target_url, core.target)].each do |instance|
|
|
expect(instance).to respond_to(:directory_listing?)
|
|
expect(instance).to respond_to(:directory_listing_entries)
|
|
|
|
# The below doesn't work, the module would have to be removed from the class
|
|
# TODO: find a way to test this
|
|
# expect(instance.server).to eql @expected if instance.is_a? WPScan::Model::WpItem
|
|
end
|
|
end
|
|
|
|
context 'when no --server supplied' do
|
|
%i[Apache IIS Nginx].each do |server|
|
|
it "loads the #{server} module and returns :#{server}" do
|
|
@stubbed_server = server
|
|
@expected = server
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when --server' do
|
|
%i[apache iis nginx].each do |server|
|
|
context "when #{server}" do
|
|
let(:cli_args) { "#{super()} --server #{server}" }
|
|
let(:servers) { [:Apache, nil, :IIS, :Nginx] }
|
|
|
|
it "loads the #{server.capitalize} module and returns :#{server}" do
|
|
@stubbed_server = servers.sample
|
|
@expected = server == :iis ? :IIS : server.to_s.camelize.to_sym
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#update_db_required?' do
|
|
context 'when missing files' do
|
|
before { expect(core.local_db).to receive(:missing_files?).ordered.and_return(true) }
|
|
|
|
context 'when --no-update' do
|
|
let(:cli_args) { "#{super()} --no-update" }
|
|
|
|
it 'raises an error' do
|
|
expect { core.update_db_required? }.to raise_error(WPScan::Error::MissingDatabaseFile)
|
|
end
|
|
end
|
|
|
|
context 'otherwise' do
|
|
its(:update_db_required?) { should eql true }
|
|
end
|
|
end
|
|
|
|
context 'when not missing files' do
|
|
before { expect(core.local_db).to receive(:missing_files?).ordered.and_return(false) }
|
|
|
|
context 'when --update' do
|
|
let(:cli_args) { "#{super()} --update" }
|
|
|
|
its(:update_db_required?) { should eql true }
|
|
end
|
|
|
|
context 'when --no-update' do
|
|
let(:cli_args) { "#{super()} --no-update" }
|
|
|
|
its(:update_db_required?) { should eql false }
|
|
end
|
|
|
|
context 'when user_interation (i.e cli output)' do
|
|
let(:cli_args) { "#{super()} --format cli" }
|
|
|
|
context 'when the db is up-to-date' do
|
|
before { expect(core.local_db).to receive(:outdated?).and_return(false) }
|
|
|
|
its(:update_db_required?) { should eql false }
|
|
end
|
|
|
|
context 'when the db is outdated' do
|
|
before do
|
|
expect(core.local_db).to receive(:outdated?).ordered.and_return(true)
|
|
expect(core.formatter).to receive(:output).with('@notice', hash_including(:msg), 'core').ordered
|
|
expect($stdout).to receive(:write).ordered # for the print()
|
|
end
|
|
|
|
context 'when a positive answer' do
|
|
before { expect(Readline).to receive(:readline).and_return('Yes').ordered }
|
|
|
|
its(:update_db_required?) { should eql true }
|
|
end
|
|
|
|
context 'when a negative answer' do
|
|
before { expect(Readline).to receive(:readline).and_return('no').ordered }
|
|
|
|
its(:update_db_required?) { should eql false }
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when no user_interation' do
|
|
let(:cli_args) { "#{super()} --format json" }
|
|
|
|
its(:update_db_required?) { should eql false }
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#before_scan' do
|
|
before do
|
|
stub_request(:get, target_url)
|
|
|
|
expect(core.formatter).to receive(:output).with('banner', hash_including(verbose: nil), 'core')
|
|
|
|
expect(core).to receive(:update_db_required?).and_return(false) unless WPScan::ParsedCli.update
|
|
end
|
|
|
|
context 'when --update' do
|
|
before do
|
|
expect(core.formatter).to receive(:output)
|
|
.with('db_update_started', hash_including(verbose: nil), 'core').ordered
|
|
|
|
expect_any_instance_of(WPScan::DB::Updater).to receive(:update)
|
|
|
|
expect(core.formatter).to receive(:output)
|
|
.with('db_update_finished', hash_including(verbose: nil), 'core').ordered
|
|
end
|
|
|
|
context 'when the --url is not supplied' do
|
|
let(:cli_args) { '--update' }
|
|
|
|
it 'calls the formatter when started and finished to update the db and exit' do
|
|
expect { core.before_scan }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
context 'when --url is supplied' do
|
|
let(:cli_args) { "#{super()} --update" }
|
|
|
|
before do
|
|
expect(core).to receive(:load_server_module)
|
|
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
|
expect(core.target).to receive(:wordpress_hosted?).and_return(false)
|
|
end
|
|
|
|
it 'calls the formatter when started and finished to update the db' do
|
|
expect { core.before_scan }.to_not raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when hosted on wordpress.com' do
|
|
let(:target_url) { 'http://ex.wordpress.com' }
|
|
|
|
before { expect(core).to receive(:load_server_module) }
|
|
|
|
it 'raises an error' do
|
|
expect { core.before_scan }.to raise_error(WPScan::Error::WordPressHosted)
|
|
end
|
|
end
|
|
|
|
context 'when not hosted on wordpress.com' do
|
|
before { allow(core.target).to receive(:wordpress_hosted?).and_return(false) }
|
|
|
|
context 'when a redirect occurs' do
|
|
before do
|
|
stub_request(:any, target_url)
|
|
|
|
expect(core.target).to receive(:homepage_res)
|
|
.at_least(1)
|
|
.and_return(Typhoeus::Response.new(effective_url: redirection, body: ''))
|
|
end
|
|
|
|
context 'to the wp-admin/install.php' do
|
|
let(:redirection) { "#{target_url}wp-admin/install.php" }
|
|
|
|
it 'calls the formatter with the correct parameters and exit' do
|
|
expect(core.formatter).to receive(:output)
|
|
.with('not_fully_configured', hash_including(url: redirection), 'core').ordered
|
|
|
|
# TODO: Would be cool to be able to test the exit code
|
|
expect { core.before_scan }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
context 'to something else' do
|
|
let(:redirection) { 'http://g.com/' }
|
|
|
|
it 'raises an error' do
|
|
expect { core.before_scan }.to raise_error(CMSScanner::Error::HTTPRedirect)
|
|
end
|
|
end
|
|
|
|
context 'to another path with the wp-admin/install.php in the query' do
|
|
let(:redirection) { "#{target_url}index.php?a=/wp-admin/install.php" }
|
|
|
|
context 'when wordpress' do
|
|
it 'does not raise an error' do
|
|
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
|
|
|
expect { core.before_scan }.to_not raise_error
|
|
end
|
|
end
|
|
|
|
context 'when not wordpress' do
|
|
it 'raises an error' do
|
|
expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false)
|
|
|
|
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when wordpress' do
|
|
before do
|
|
expect(core).to receive(:load_server_module)
|
|
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
|
end
|
|
|
|
it 'does not raise any error' do
|
|
expect { core.before_scan }.to_not raise_error
|
|
end
|
|
end
|
|
|
|
context 'when not wordpress' do
|
|
before do
|
|
expect(core).to receive(:load_server_module)
|
|
end
|
|
|
|
context 'when no --force' do
|
|
before { expect(core.target).to receive(:maybe_add_cookies) }
|
|
|
|
context 'when no cookies added or still not wordpress after being added' do
|
|
it 'raises an error' do
|
|
expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false)
|
|
|
|
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
|
|
end
|
|
end
|
|
|
|
context 'when the added cookies solved it' do
|
|
it 'does not raise an error' do
|
|
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false).ordered
|
|
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true).ordered
|
|
|
|
expect { core.before_scan }.to_not raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when --force' do
|
|
let(:cli_args) { "#{super()} --force" }
|
|
|
|
it 'does not raise any error' do
|
|
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false)
|
|
|
|
expect { core.before_scan }.to_not raise_error
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|