HELLO v3!!!
This commit is contained in:
38
spec/app/controllers/aliases_spec.rb
Normal file
38
spec/app/controllers/aliases_spec.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::Aliases do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
let(:parsed_options) { rspec_parsed_options(cli_args) }
|
||||
let(:cli_args) { "--url #{target_url}" }
|
||||
|
||||
before do
|
||||
WPScan::Browser.reset
|
||||
described_class.parsed_options = parsed_options
|
||||
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
|
||||
expect(controller.cli_options.map(&:to_sym)).to eq %i[stealthy]
|
||||
end
|
||||
end
|
||||
|
||||
describe 'parsed_options' do
|
||||
context 'when no --stealthy supplied' do
|
||||
its(:parsed_options) { should eql parsed_options }
|
||||
end
|
||||
|
||||
context 'when --stealthy supplied' do
|
||||
let(:cli_args) { "#{super()} --stealthy" }
|
||||
|
||||
it 'contains the correct options' do
|
||||
expect(controller.parsed_options).to include(
|
||||
random_user_agent: true, detection_mode: :passive, plugins_version_detection: :passive
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
271
spec/app/controllers/core_spec.rb
Normal file
271
spec/app/controllers/core_spec.rb
Normal file
@@ -0,0 +1,271 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::Core do
|
||||
subject(:core) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
let(:parsed_options) { rspec_parsed_options(cli_args) }
|
||||
let(:cli_args) { "--url #{target_url}" }
|
||||
|
||||
before do
|
||||
WPScan::Browser.reset
|
||||
described_class.reset
|
||||
described_class.parsed_options = parsed_options
|
||||
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 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::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::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}" }
|
||||
|
||||
it "loads the #{server.capitalize} module and returns :#{server}" do
|
||||
@stubbed_server = [:Apache, nil, :IIS, :Nginx].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::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 parsed_options[: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?).and_return(true)
|
||||
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 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::HTTPRedirectError)
|
||||
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?).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?).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to raise_error(WPScan::NotWordPressError)
|
||||
end
|
||||
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::WordPressHostedError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wordpress' do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).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)
|
||||
expect(core.target).to receive(:wordpress?).and_return(false)
|
||||
end
|
||||
|
||||
context 'when no --force' do
|
||||
it 'raises an error' do
|
||||
expect { core.before_scan }.to raise_error(WPScan::NotWordPressError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when --force' do
|
||||
let(:cli_args) { "#{super()} --force" }
|
||||
|
||||
it 'does not raise any error' do
|
||||
expect { core.before_scan }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
45
spec/app/controllers/custom_directories_spec.rb
Normal file
45
spec/app/controllers/custom_directories_spec.rb
Normal file
@@ -0,0 +1,45 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::CustomDirectories do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
let(:parsed_options) { rspec_parsed_options(cli_args) }
|
||||
let(:cli_args) { "--url #{target_url}" }
|
||||
|
||||
before do
|
||||
WPScan::Browser.reset
|
||||
described_class.parsed_options = parsed_options
|
||||
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
|
||||
expect(controller.cli_options.map(&:to_sym)).to eq %i[wp_content_dir wp_plugins_dir]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#before_scan' do
|
||||
context 'when the content_dir is not found and not supply' do
|
||||
before { expect(controller.target).to receive(:content_dir) }
|
||||
|
||||
let(:exception) do
|
||||
'Unable to identify the wp-content dir, please supply it with --wp-content-dir'
|
||||
end
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { controller.before_scan }.to raise_error(exception)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when content_dir found/supplied' do
|
||||
let(:cli_args) { "#{super()} --wp-content-dir wp-content" }
|
||||
|
||||
it 'does not raise any error' do
|
||||
expect { controller.before_scan }.to_not raise_error
|
||||
expect(controller.target.content_dir).to eq parsed_options[:wp_content_dir]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
180
spec/app/controllers/enumeration_spec.rb
Normal file
180
spec/app/controllers/enumeration_spec.rb
Normal file
@@ -0,0 +1,180 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::Enumeration do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://wp.lab/' }
|
||||
let(:parsed_options) { rspec_parsed_options(cli_args) }
|
||||
let(:cli_args) { "--url #{target_url}" }
|
||||
|
||||
before do
|
||||
WPScan::Browser.reset
|
||||
|
||||
## For the --passwords options
|
||||
allow_any_instance_of(OptParseValidator::OptPath).to receive(:check_file)
|
||||
|
||||
described_class.parsed_options = parsed_options
|
||||
end
|
||||
|
||||
describe '#enum_message' do
|
||||
after { expect(controller.enum_message(type)).to eql @expected }
|
||||
|
||||
context 'when type argument is incorrect' do
|
||||
let(:type) { 'spec' }
|
||||
|
||||
it 'returns nil' do
|
||||
@expected = nil
|
||||
end
|
||||
end
|
||||
|
||||
%w[plugins themes].each do |t|
|
||||
context "type = #{t}" do
|
||||
let(:type) { t }
|
||||
|
||||
context 'when vulnerable' do
|
||||
let(:cli_args) { "#{super()} -e v#{type[0]}" }
|
||||
|
||||
it 'returns the expected string' do
|
||||
@expected = "Enumerating Vulnerable #{type.capitalize}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when all' do
|
||||
let(:cli_args) { "#{super()} -e a#{type[0]}" }
|
||||
|
||||
it 'returns the expected string' do
|
||||
@expected = "Enumerating All #{type.capitalize}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when most popular' do
|
||||
let(:cli_args) { "#{super()} -e #{type[0]}" }
|
||||
|
||||
it 'returns the expected string' do
|
||||
@expected = "Enumerating Most Popular #{type.capitalize}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#default_opts' do
|
||||
context 'when no --enumerate' do
|
||||
it 'contains the correct version_detection' do
|
||||
expect(controller.default_opts('plugins')[:version_detection]).to include(mode: :mixed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cli_options' do
|
||||
it 'contains the correct options' do
|
||||
expect(controller.cli_options.map(&:to_sym)).to eql(
|
||||
%i[enumerate exclude_content_based
|
||||
plugins_list plugins_detection plugins_version_all plugins_version_detection
|
||||
themes_list themes_detection themes_version_all themes_version_detection
|
||||
timthumbs_list timthumbs_detection
|
||||
config_backups_list config_backups_detection
|
||||
db_exports_list db_exports_detection
|
||||
medias_detection
|
||||
users_list users_detection]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#enum_users' do
|
||||
before { expect(controller.formatter).to receive(:output).twice }
|
||||
after { controller.enum_users }
|
||||
|
||||
context 'when --enumerate has been supplied' do
|
||||
let(:cli_args) { "#{super()} -e u1-10" }
|
||||
|
||||
it 'calls the target.users with the correct range' do
|
||||
expect(controller.target).to receive(:users).with(hash_including(range: (1..10)))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when --passwords supplied but no --username or --usernames' do
|
||||
let(:cli_args) { "#{super()} --passwords some-file.txt" }
|
||||
|
||||
it 'calls the target.users with the default range' do
|
||||
expect(controller.target).to receive(:users).with(hash_including(range: (1..10)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#before_scan' do
|
||||
it 'creates the Dynamic Finders' do
|
||||
expect(WPScan::DB::DynamicFinders::Plugin).to receive(:create_versions_finders)
|
||||
expect(WPScan::DB::DynamicFinders::Theme).to receive(:create_versions_finders)
|
||||
|
||||
controller.before_scan
|
||||
end
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
context 'when no :enumerate' do
|
||||
before do
|
||||
expect(controller).to receive(:enum_plugins)
|
||||
expect(controller).to receive(:enum_config_backups)
|
||||
|
||||
expect(parsed_options[:plugins_detection]).to eql :passive
|
||||
end
|
||||
|
||||
it 'calls enum_plugins and enum_config_backups' do
|
||||
controller.run
|
||||
end
|
||||
|
||||
context 'when --passwords supplied but no --username or --usernames' do
|
||||
let(:cli_args) { "#{super()} --passwords some-file.txt" }
|
||||
|
||||
it 'calls the enum_users' do
|
||||
expect(controller).to receive(:enum_users)
|
||||
controller.run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :enumerate' do
|
||||
after { controller.run }
|
||||
|
||||
context 'when no option supplied' do
|
||||
let(:cli_args) { "#{super()} -e" }
|
||||
|
||||
it 'calls the correct enum methods' do
|
||||
%i[plugins themes timthumbs config_backups db_exports users medias].each do |option|
|
||||
expect(controller).to receive("enum_#{option}".to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%i[p ap vp].each do |option|
|
||||
context "when #{option}" do
|
||||
let(:cli_args) { "#{super()} -e #{option}" }
|
||||
|
||||
it 'calls the #enum_plugins' do
|
||||
expect(controller).to receive(:enum_plugins)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%i[t at vt].each do |option|
|
||||
context option.to_s do
|
||||
let(:cli_args) { "#{super()} -e #{option}" }
|
||||
|
||||
it 'calls the #enum_themes' do
|
||||
expect(controller).to receive(:enum_themes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
{ timthumbs: 'tt', config_backups: 'cb', db_exports: 'dbe', medias: 'm', users: 'u' }.each do |option, shortname|
|
||||
context "when #{option}" do
|
||||
let(:cli_args) { "#{super()} -e #{shortname}" }
|
||||
|
||||
it "calls the ##{option}" do
|
||||
expect(controller).to receive("enum_#{option}".to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
169
spec/app/controllers/password_attack_spec.rb
Normal file
169
spec/app/controllers/password_attack_spec.rb
Normal file
@@ -0,0 +1,169 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::PasswordAttack do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
let(:parsed_options) { rspec_parsed_options(cli_args) }
|
||||
let(:cli_args) { "--url #{target_url}" }
|
||||
|
||||
before do
|
||||
WPScan::Browser.reset
|
||||
described_class.parsed_options = parsed_options
|
||||
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
|
||||
expect(controller.cli_options.map(&:to_sym))
|
||||
.to eq(%i[passwords usernames multicall_max_passwords password_attack])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#users' do
|
||||
context 'when no --usernames' do
|
||||
it 'calles target.users' do
|
||||
expect(controller.target).to receive(:users)
|
||||
controller.users
|
||||
end
|
||||
end
|
||||
|
||||
context 'when --usernames' do
|
||||
let(:cli_args) { "#{super()} --usernames admin,editor" }
|
||||
|
||||
it 'returns an array with the users' do
|
||||
expected = %w[admin editor].reduce([]) do |a, e|
|
||||
a << CMSScanner::User.new(e)
|
||||
end
|
||||
|
||||
expect(controller.users).to eql expected
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#passwords' do
|
||||
xit
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
context 'when no --passwords is supplied' do
|
||||
it 'does not run the attacker' do
|
||||
expect(controller.run).to eql nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#attacker' do
|
||||
context 'when --password-attack provided' do
|
||||
let(:cli_args) { "#{super()} --password-attack #{attack}" }
|
||||
|
||||
context 'when wp-login' do
|
||||
let(:attack) { 'wp-login' }
|
||||
|
||||
it 'returns the correct object' do
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
|
||||
expect(controller.attacker.target).to be_a WPScan::Target
|
||||
end
|
||||
end
|
||||
|
||||
context 'when xmlrpc' do
|
||||
before do
|
||||
expect(controller.target).to receive(:xmlrpc).and_return(WPScan::XMLRPC.new("#{target_url}/xmlrpc.php"))
|
||||
end
|
||||
|
||||
context 'when single xmlrpc' do
|
||||
let(:attack) { 'xmlrpc' }
|
||||
|
||||
it 'returns the correct object' do
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
|
||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||
end
|
||||
end
|
||||
|
||||
context 'when xmlrpc-multicall' do
|
||||
let(:attack) { 'xmlrpc-multicall' }
|
||||
|
||||
it 'returns the correct object' do
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPCMulticall
|
||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when automatic detection' do
|
||||
before { expect(controller.target).to receive(:xmlrpc).and_return(xmlrpc) }
|
||||
|
||||
context 'when xmlrpc not found' do
|
||||
let(:xmlrpc) { nil }
|
||||
|
||||
it 'returns the WpLogin' do
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
|
||||
expect(controller.attacker.target).to be_a WPScan::Target
|
||||
end
|
||||
end
|
||||
|
||||
context 'when xmlrpc not enabled' do
|
||||
let(:xmlrpc) { WPScan::XMLRPC.new("#{target_url}/xmlrpc.php") }
|
||||
|
||||
it 'returns the WpLogin' do
|
||||
expect(xmlrpc).to receive(:enabled?).and_return(false)
|
||||
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
|
||||
expect(controller.attacker.target).to be_a WPScan::Target
|
||||
end
|
||||
end
|
||||
|
||||
context 'when xmlrpc enabled' do
|
||||
let(:xmlrpc) { WPScan::XMLRPC.new("#{target_url}/xmlrpc.php") }
|
||||
|
||||
before { expect(xmlrpc).to receive(:enabled?).and_return(true) }
|
||||
|
||||
context 'when wp.getUsersBlogs methods not available' do
|
||||
it 'returns the WpLogin' do
|
||||
expect(xmlrpc).to receive(:available_methods).and_return(%w[m1 m2])
|
||||
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
|
||||
expect(controller.attacker.target).to be_a WPScan::Target
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wp.getUsersBlogs method evailable' do
|
||||
before { expect(xmlrpc).to receive(:available_methods).and_return(%w[wp.getUsersBlogs m2]) }
|
||||
|
||||
context 'when WP version not found' do
|
||||
it 'returns the XMLRPC' do
|
||||
expect(controller.target).to receive(:wp_version).and_return(false)
|
||||
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
|
||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||
end
|
||||
end
|
||||
|
||||
context 'when WP version found' do
|
||||
before { expect(controller.target).to receive(:wp_version).and_return(wp_version) }
|
||||
|
||||
context 'when WP < 4.4' do
|
||||
let(:wp_version) { WPScan::WpVersion.new('3.8.1') }
|
||||
|
||||
it 'returns the XMLRPCMulticall' do
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPCMulticall
|
||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||
end
|
||||
end
|
||||
|
||||
context 'when WP >= 4.4' do
|
||||
let(:wp_version) { WPScan::WpVersion.new('4.4') }
|
||||
|
||||
it 'returns the XMLRPC' do
|
||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
|
||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
85
spec/app/controllers/wp_version_spec.rb
Normal file
85
spec/app/controllers/wp_version_spec.rb
Normal file
@@ -0,0 +1,85 @@
|
||||
require 'spec_helper'
|
||||
|
||||
def it_calls_the_formatter_with_the_correct_parameter(version)
|
||||
it 'calls the formatter with the correct parameter' do
|
||||
expect(controller.formatter).to receive(:output)
|
||||
.with('version', hash_including(version: version), 'wp_version')
|
||||
end
|
||||
end
|
||||
|
||||
describe WPScan::Finders::WpVersionFinders do
|
||||
subject(:finders) { described_class.new }
|
||||
|
||||
describe 'filter_findings' do
|
||||
context 'when super returns false (nothing found)' do
|
||||
before do
|
||||
expect_any_instance_of(WPScan::Finders::UniqueFinders).to receive(:filter_findings).and_return(false)
|
||||
end
|
||||
|
||||
its(:filter_findings) { should be false }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe WPScan::Controller::WpVersion do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
let(:parsed_options) { rspec_parsed_options(cli_args) }
|
||||
let(:cli_args) { "--url #{target_url}" }
|
||||
|
||||
before do
|
||||
WPScan::Browser.reset
|
||||
described_class.parsed_options = parsed_options
|
||||
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
|
||||
expect(controller.cli_options.map(&:to_sym)).to eq %i[wp_version_all wp_version_detection]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
before do
|
||||
expect(controller.target).to receive(:wp_version)
|
||||
.with(
|
||||
hash_including(
|
||||
mode: parsed_options[:wp_version_detection] || parsed_options[:detection_mode],
|
||||
confidence_threshold: parsed_options[:wp_version_all] ? 0 : 100
|
||||
)
|
||||
).and_return(stubbed)
|
||||
end
|
||||
|
||||
after { controller.run }
|
||||
|
||||
%i[mixed passive aggressive].each do |mode|
|
||||
context "when --detection-mode #{mode}" do
|
||||
let(:cli_args) { "#{super()} --detection-mode #{mode}" }
|
||||
|
||||
[WPScan::WpVersion.new('4.0')].each do |version|
|
||||
context "when version = #{version}" do
|
||||
let(:stubbed) { version }
|
||||
|
||||
it_calls_the_formatter_with_the_correct_parameter(version)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when --wp-version-all supplied' do
|
||||
let(:cli_args) { "#{super()} --wp-version-all" }
|
||||
let(:stubbed) { WPScan::WpVersion.new('3.9.1') }
|
||||
|
||||
it_calls_the_formatter_with_the_correct_parameter(WPScan::WpVersion.new('3.9.1'))
|
||||
end
|
||||
|
||||
context 'when --wp-version-detection mode supplied' do
|
||||
let(:cli_args) { "#{super()} --detection-mode mixed --wp-version-detection passive" }
|
||||
let(:stubbed) { WPScan::WpVersion.new('4.4') }
|
||||
|
||||
it_calls_the_formatter_with_the_correct_parameter(WPScan::WpVersion.new('4.4'))
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user