diff --git a/app/controllers/core.rb b/app/controllers/core.rb index d9090b97..5c2f0d3a 100644 --- a/app/controllers/core.rb +++ b/app/controllers/core.rb @@ -52,13 +52,16 @@ module WPScan def before_scan @last_update = local_db.last_update - maybe_output_banner_help_and_version # From CMS Scanner + maybe_output_banner_help_and_version # From CMSScanner update_db if update_db_required? setup_cache check_target_availability load_server_module check_wordpress_state + rescue Error::NotWordPress => e + target.maybe_add_cookies + raise e unless target.wordpress?(parsed_options[:detection_mode]) end # Raises errors if the target is hosted on wordpress.com or is not running WordPress diff --git a/lib/wpscan/target/platform/wordpress.rb b/lib/wpscan/target/platform/wordpress.rb index 4828cbbd..8bcb1515 100644 --- a/lib/wpscan/target/platform/wordpress.rb +++ b/lib/wpscan/target/platform/wordpress.rb @@ -45,6 +45,34 @@ module WPScan false end + COOKIE_PATTERNS = { + 'vjs' => /createCookie\('vjs','(?\d+)',\d+\);/i + }.freeze + + # Sometimes there is a mechanism in place on the blog, which requires a specific + # cookie and value to be added to requests. Lets try to detect and add them + def maybe_add_cookies + COOKIE_PATTERNS.each do |cookie_key, pattern| + next unless homepage_res.body =~ pattern + + browser = Browser.instance + + cookie_string = "#{cookie_key}=#{Regexp.last_match[:c_value]}" + + cookie_string += "; #{browser.cookie_string}" if browser.cookie_string + + browser.cookie_string = cookie_string + + # Force recheck of the homepage when retying wordpress? + # No need to clear the cache, as the request (which will contain the cookies) + # will be different + @homepage_res = nil + @homepage_url = nil + + break + end + end + # @return [ String ] def registration_url multisite? ? url('wp-signup.php') : url('wp-login.php?action=register') diff --git a/spec/app/controllers/core_spec.rb b/spec/app/controllers/core_spec.rb index 66c1050a..1fc70575 100644 --- a/spec/app/controllers/core_spec.rb +++ b/spec/app/controllers/core_spec.rb @@ -218,7 +218,7 @@ describe WPScan::Controller::Core do context 'when not wordpress' do it 'raises an error' do - expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false) + expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false) expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress) end @@ -250,12 +250,26 @@ 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?).with(:mixed).and_return(false) end context 'when no --force' do - it 'raises an error' do - expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress) + 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 @@ -263,6 +277,8 @@ describe WPScan::Controller::Core 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 diff --git a/spec/fixtures/target/platform/wordpress/maybe_add_cookies/vjs.html b/spec/fixtures/target/platform/wordpress/maybe_add_cookies/vjs.html new file mode 100644 index 00000000..ce98160f --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/maybe_add_cookies/vjs.html @@ -0,0 +1,24 @@ + + + + + + +
+ +

Access to this website is possible only using browser with JavaScript and Cookies enabled.

diff --git a/spec/shared_examples/target/platform/wordpress.rb b/spec/shared_examples/target/platform/wordpress.rb index 325c04a8..b827c40b 100644 --- a/spec/shared_examples/target/platform/wordpress.rb +++ b/spec/shared_examples/target/platform/wordpress.rb @@ -68,6 +68,76 @@ shared_examples WPScan::Target::Platform::WordPress do end end + describe '#maybe_add_cookies' do + let(:fixtures) { super().join('maybe_add_cookies') } + let(:browser) { WPScan::Browser.instance } + + context 'when nothing matches' do + it 'does nothing' do + stub_request(:get, target.url).to_return(body: 'nothing there') + + subject.maybe_add_cookies + + expect(browser.cookie_string).to eql nil + expect(subject.homepage_res.body).to eql 'nothing there' + end + end + + context 'when matches' do + before do + stub_request(:get, target.url) + .to_return( + { body: File.read(fixtures.join("#{cookie}.html")) }, + body: 'Cookies Accepted!' # if we put {} there, ruobop not happy! + ) + end + + { + 'vjs' => 'vjs=2420671338' + }.each do |key, expected_cookie_string| + context "when #{key} match" do + let(:cookie) { key } + + context 'when the browser does not have a cookie_string already' do + before do + subject.maybe_add_cookies + + # This one does not work, opened an issue + # https://github.com/bblimke/webmock/issues/813 + # stub_request(:get, target.url) + # .with(headers: { 'Cookie' => expected_cookie_string }) + # .to_return(body: 'Cookies Accepted!') + end + + it 'sets the correct cookies, reset the homepage_res' do + expect(browser.cookie_string).to eql expected_cookie_string + expect(subject.homepage_res.body).to eql 'Cookies Accepted!' + end + end + + context 'when the browser has cookie_string already' do + before do + browser.cookie_string = 'key=no-override' + + subject.maybe_add_cookies + + # This one does not work, opened an issue + # https://github.com/bblimke/webmock/issues/813 + # stub_request(:get, target.url) + # .with(headers: { 'Cookie' => "#{expected_cookie_string}; key=no-override" }) + # .to_return(body: 'Cookies Accepted!') + end + + it 'sets the correct cookies, reset the homepage_res' do + expect(browser.cookie_string).to eql "#{expected_cookie_string}; key=no-override" + expect(subject.homepage_res.body).to eql 'Cookies Accepted!' + end + end + end + end + end + end + describe '#wordpress_hosted?' do its(:wordpress_hosted?) { should be false }