diff --git a/app/controllers/core.rb b/app/controllers/core.rb index d2c6ab79..2af48df9 100644 --- a/app/controllers/core.rb +++ b/app/controllers/core.rb @@ -71,7 +71,7 @@ module WPScan exit(WPScan::ExitCode::VULNERABLE) end - raise NotWordPressError unless target.wordpress? || parsed_options[:force] + raise NotWordPressError unless target.wordpress?(parsed_options[:detection_mode]) || parsed_options[:force] end # Loads the related server module in the target diff --git a/lib/wpscan/target/platform/wordpress.rb b/lib/wpscan/target/platform/wordpress.rb index 9c86613c..033cb54f 100644 --- a/lib/wpscan/target/platform/wordpress.rb +++ b/lib/wpscan/target/platform/wordpress.rb @@ -18,10 +18,10 @@ module WPScan alias registration_enabled? registration_enabled alias mu_plugins? mu_plugins + # @param [ Symbol ] detection_mode + # # @return [ Boolean ] - def wordpress? - # res = Browser.get(url) - + def wordpress?(detection_mode) in_scope_urls(homepage_res) do |url| return true if Addressable::URI.parse(url).path.match(WORDPRESS_PATTERN) end @@ -32,6 +32,14 @@ module WPScan return true unless comments_from_page(/wordpress/i, homepage_res).empty? + if %i[mixed aggressive].include?(detection_mode) + %w[wp-admin/install.php wp-login.php].each do |path| + in_scope_urls(Browser.get_and_follow_location(url(path))).each do |url| + return true if Addressable::URI.parse(url).path.match(WORDPRESS_PATTERN) + end + end + end + false end diff --git a/spec/app/controllers/core_spec.rb b/spec/app/controllers/core_spec.rb index 27e19ac2..01d517f8 100644 --- a/spec/app/controllers/core_spec.rb +++ b/spec/app/controllers/core_spec.rb @@ -165,7 +165,7 @@ describe WPScan::Controller::Core do before do expect(core).to receive(:load_server_module) - expect(core.target).to receive(:wordpress?).and_return(true) + expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true) end it 'calls the formatter when started and finished to update the db' do @@ -208,7 +208,7 @@ describe WPScan::Controller::Core do context 'when wordpress' do it 'does not raise an error' do - expect(core.target).to receive(:wordpress?).and_return(true) + expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true) expect { core.before_scan }.to_not raise_error end @@ -216,7 +216,7 @@ describe WPScan::Controller::Core do context 'when not wordpress' do it 'raises an error' do - expect(core.target).to receive(:wordpress?).and_return(false) + expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false) expect { core.before_scan }.to raise_error(WPScan::NotWordPressError) end @@ -237,7 +237,7 @@ describe WPScan::Controller::Core do context 'when wordpress' do before do expect(core).to receive(:load_server_module) - expect(core.target).to receive(:wordpress?).and_return(true) + expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true) end it 'does not raise any error' do @@ -248,7 +248,7 @@ describe WPScan::Controller::Core do context 'when not wordpress' do before do expect(core).to receive(:load_server_module) - expect(core.target).to receive(:wordpress?).and_return(false) + expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false) end context 'when no --force' do diff --git a/spec/fixtures/target/platform/wordpress/detection/wp-admin-install.php b/spec/fixtures/target/platform/wordpress/detection/wp-admin-install.php new file mode 100644 index 00000000..9ea119b5 --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/detection/wp-admin-install.php @@ -0,0 +1,15 @@ + + + + + + + WordPress › Installation + + + + + + + +

Already Installed

You appear to have already installed WordPress. To reinstall please clear your old database tables first.

Log In

diff --git a/spec/fixtures/target/platform/wordpress/detection/wp-login.php b/spec/fixtures/target/platform/wordpress/detection/wp-login.php new file mode 100644 index 00000000..9affc3ca --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/detection/wp-login.php @@ -0,0 +1,68 @@ + + + + + + + + Log In WP Lab + + + + + + + + + + + +
+

WP Lab

+ +
+

+ +

+

+ +

+

+

+ + + +

+
+ + + + + +

← Back to WP Lab

+ +
+ + +
+ + + diff --git a/spec/shared_examples/target/platform/wordpress.rb b/spec/shared_examples/target/platform/wordpress.rb index 6f2ca601..609e2285 100644 --- a/spec/shared_examples/target/platform/wordpress.rb +++ b/spec/shared_examples/target/platform/wordpress.rb @@ -3,28 +3,65 @@ require_relative 'wordpress/custom_directories' shared_examples WPScan::Target::Platform::WordPress do it_behaves_like 'WordPress::CustomDirectories' - let(:fixtures) { File.join(FIXTURES, 'target', 'platform', 'wordpress') } + let(:fixtures) { FIXTURES.join('target', 'platform', 'wordpress') } describe '#wordpress?' do - let(:fixtures) { File.join(super(), 'detection') } + let(:fixtures) { super().join('detection') } before do - stub_request(:get, target.url).to_return(body: File.read(File.join(fixtures, "#{body}.html"))) + stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{homepage}.html"))) end - %w[default wp_includes only_scripts meta_generator comments mu_plugins].each do |file| - context "when a wordpress page (#{file}.html)" do - let(:body) { file } + context 'when pattern/s in the homepage' do + %w[default wp_includes only_scripts meta_generator comments mu_plugins].each do |file| + context "when a wordpress page (#{file}.html)" do + let(:homepage) { file } - its(:wordpress?) { should be true } + it 'returns true' do + expect(subject.wordpress?(:mixed)).to be true + end + end end end - %w[not_wp].each do |file| - context "when not a wordpress page (#{file}.html)" do - let(:body) { file } + context 'when no clues in the homepage' do + let(:homepage) { 'not_wp' } - its(:wordpress?) { should be false } + context 'when only passive detection mode' do + it 'returns false' do + expect(subject.wordpress?(:passive)).to be false + end + end + + context 'when mixed or aggressive detection modes' do + context 'when wp-admin/install.php and wp-login.php not there' do + it 'returns false' do + %w[wp-admin/install.php wp-login.php].each do |path| + stub_request(:get, target.url(path)).to_return(status: 404) + end + + expect(subject.wordpress?(:mixed)).to be false + end + end + + context 'when wp-admin/install.php is matching a WP install' do + it 'returns true' do + stub_request(:get, target.url('wp-admin/install.php')) + .to_return(body: File.read(fixtures.join('wp-admin-install.php'))) + + expect(subject.wordpress?(:mixed)).to be true + end + end + + context 'when wp-admin/install.php not there but wp-login.php is matching a WP install' do + it 'returns true' do + stub_request(:get, target.url('wp-admin/install.php')).to_return(status: 404) + stub_request(:get, target.url('wp-login.php')) + .to_return(body: File.read(fixtures.join('wp-login.php'))) + + expect(subject.wordpress?(:mixed)).to be true + end + end end end end