Path: blob/master/spec/shared_examples/target/platform/wordpress.rb
485 views
# frozen_string_literal: true12require_relative 'wordpress/custom_directories'34shared_examples WPScan::Target::Platform::WordPress do5it_behaves_like 'WordPress::CustomDirectories'67let(:fixtures) { FIXTURES.join('target', 'platform', 'wordpress') }89describe '#wordpress?, wordpress_from_meta_comments_or_scripts?' do10let(:fixtures) { super().join('detection') }1112before do13stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{homepage}.html")))14stub_request(:get, ERROR_404_URL_PATTERN).to_return(body: File.read(fixtures.join("#{page404}.html")))15end1617context 'when pattern/s in the homepage' do18let(:page404) { 'not_wp' }1920%w[default wp_includes only_scripts meta_generator comments mu_plugins wp_admin wp_json_oembed].each do |file|21context "when a wordpress page (#{file}.html)" do22let(:homepage) { file }2324it 'returns true' do25expect(subject.wordpress?(:mixed)).to be true26end27end28end29end3031context 'when no clues in the homepage' do32let(:homepage) { 'not_wp' }3334context 'when pattern/s in the 404 page' do35%w[default wp_includes only_scripts meta_generator comments mu_plugins wp_admin wp_json_oembed].each do |file|36context "when a wordpress page (#{file}.html)" do37let(:page404) { file }3839it 'returns true' do40expect(subject.wordpress?(:mixed)).to be true41end42end43end44end4546context 'when no clues in the 404 page' do47let(:page404) { 'not_wp' }4849context 'when only passive detection mode' do50it 'returns false' do51expect(subject.wordpress?(:passive)).to be false52end53end5455context 'when mixed or aggressive detection modes' do56context 'when wp-admin/install.php and wp-login.php not there' do57it 'returns false' do58%w[wp-admin/install.php wp-login.php].each do |path|59stub_request(:get, target.url(path)).to_return(status: 404)60end6162expect(subject.wordpress?(:mixed)).to be false63end64end6566context 'when wp-admin/install.php is matching a WP install' do67it 'returns true' do68stub_request(:get, target.url('wp-admin/install.php'))69.to_return(body: File.read(fixtures.join('wp-admin-install.php')))7071expect(subject.wordpress?(:mixed)).to be true72end73end7475context 'when wp-admin/install.php not there but wp-login.php is matching a WP install' do76it 'returns true' do77stub_request(:get, target.url('wp-admin/install.php')).to_return(status: 404)78stub_request(:get, target.url('wp-login.php'))79.to_return(body: File.read(fixtures.join('wp-login.php')))8081expect(subject.wordpress?(:mixed)).to be true82end83end8485context 'when a lot of irrelevant links' do86let(:body) do87Array.new(250) do |i|88"<a href='#{subject.url}#{i}.html>Link</a><img src='#subject.{url}img-#{i}.png'/>"89end.join("\n")90end9192it 'should not take a while to process check' do93stub_request(:get, target.url('wp-admin/install.php')).to_return(body: body)94stub_request(:get, target.url('wp-login.php')).to_return(body: body)9596time_start = Time.now97expect(subject.wordpress?(:mixed)).to be false98time_end = Time.now99100expect(time_end - time_start).to be < 1101end102end103end104end105end106end107108describe '#maybe_add_cookies' do109let(:fixtures) { super().join('maybe_add_cookies') }110let(:browser) { WPScan::Browser.instance }111112context 'when nothing matches' do113it 'does nothing' do114stub_request(:get, target.url).to_return(body: 'nothing there')115116subject.maybe_add_cookies117118expect(browser.cookie_string).to eql nil119expect(subject.homepage_res.body).to eql 'nothing there'120end121end122123context 'when matches' do124before do125stub_request(:get, target.url)126.to_return(127{ body: File.read(fixtures.join("#{cookie}.html")) },128body: 'Cookies Accepted!' # if we put {} there, ruobop not happy!129)130end131132{133'vjs' => 'vjs=2420671338'134}.each do |key, expected_cookie_string|135context "when #{key} match" do136let(:cookie) { key }137138context 'when the browser does not have a cookie_string already' do139before do140subject.maybe_add_cookies141142# This one does not work, opened an issue143# https://github.com/bblimke/webmock/issues/813144# stub_request(:get, target.url)145# .with(headers: { 'Cookie' => expected_cookie_string })146# .to_return(body: 'Cookies Accepted!')147end148149it 'sets the correct cookies, reset the homepage_res' do150expect(browser.cookie_string).to eql expected_cookie_string151expect(subject.homepage_res.body).to eql 'Cookies Accepted!'152end153end154155context 'when the browser has cookie_string already' do156before do157browser.cookie_string = 'key=no-override'158159subject.maybe_add_cookies160161# This one does not work, opened an issue162# https://github.com/bblimke/webmock/issues/813163# stub_request(:get, target.url)164# .with(headers: { 'Cookie' => "#{expected_cookie_string}; key=no-override" })165# .to_return(body: 'Cookies Accepted!')166end167168it 'sets the correct cookies, reset the homepage_res' do169expect(browser.cookie_string).to eql "#{expected_cookie_string}; key=no-override"170expect(subject.homepage_res.body).to eql 'Cookies Accepted!'171end172end173end174end175end176end177178describe '#wordpress_hosted?' do179let(:fixtures) { super().join('wordpress_hosted') }180181context 'when the target host matches' do182let(:url) { 'http://ex.wordpress.com' }183184its(:wordpress_hosted?) { should be true }185end186187context 'when the target host doesn\'t matches' do188let(:url) { 'http://ex-wordpress.com' }189190context 'when wp-content not detected' do191before do192expect(target).to receive(:content_dir).and_return(nil)193194stub_request(:get, target.url)195.to_return(body: defined?(body) ? body : File.read(fixtures.join(fixture).to_s))196end197198context 'when an src URL matches a WP hosted' do199let(:fixture) { 'match_src.html' }200201its(:wordpress_hosted?) { should be true }202end203204context 'when an href URL matches a WP hosted' do205let(:fixture) { 'match_href.html' }206207its(:wordpress_hosted?) { should be true }208end209210context 'when URLs don\'t match' do211let(:fixture) { 'no_match.html' }212213its(:wordpress_hosted?) { should be false }214end215216context 'when a lof of unrelated urls' do217let(:body) do218Array.new(250) { |i| "<a href='#{url}#{i}.html'>Some Link</a><img src='#{url}img-#{i}.png'/>" }.join("\n")219end220221it 'should not take a while to process the page' do222time_start = Time.now223expect(target.wordpress_hosted?).to be false224time_end = Time.now225226expect(time_end - time_start).to be < 1227end228end229end230231context 'when wp-content detected' do232before { expect(target).to receive(:content_dir).and_return('wp-content') }233234its(:wordpress_hosted?) { should be false }235end236end237end238239describe '#login_url' do240before do241allow(target).to receive(:sub_dir)242243WPScan::ParsedCli.options = rspec_parsed_options(cli_args)244end245246let(:cli_args) { '--url https://ex.lo' }247248context 'when login_uri CLI option set' do249let(:cli_args) { "#{super()} --login_uri other-login.php" }250251its(:login_url) { should eql target.url('other-login.php') }252end253254context 'when returning a 200' do255before { stub_request(:get, target.url('wp-login.php')).to_return(status: 200) }256257its(:login_url) { should eql target.url('wp-login.php') }258end259260context 'when a 404' do261before { stub_request(:get, target.url('wp-login.php')).to_return(status: 404) }262263its(:login_url) { should eql false }264end265266context 'when a redirection occured' do267before do268expect(WPScan::Browser).to receive(:get_and_follow_location)269.and_return(Typhoeus::Response.new(effective_url: effective_url, body: ''))270end271272context 'to an in scope URL' do273context 'when https version of the wp-login' do274let(:effective_url) { target.url('wp-login.php').gsub('http', 'https') }275276its(:login_url) { should eql effective_url }277end278279context 'when something else' do280let(:effective_url) { target.url('something').gsub('http', 'https') }281282its(:login_url) { should eql target.url('wp-login.php') }283end284end285286context 'to an out of scope URL' do287let(:effective_url) { 'http://something.else' }288289its(:login_url) { should eql target.url('wp-login.php') }290end291end292end293end294295296