From 08c574aff8ac093316110b8c04d762df761aacf5 Mon Sep 17 00:00:00 2001 From: erwanlr Date: Wed, 17 Apr 2019 15:51:56 +0100 Subject: [PATCH] Improves detection of wp-content folder --- .../platform/wordpress/custom_directories.rb | 12 ++++++------ .../custom_directories/in_meta_content.html | 5 +++++ .../wordpress/custom_directories/scope.html | 5 +++++ .../custom_directories/scope_meta_content.html | 5 +++++ spec/lib/target_spec.rb | 3 ++- .../platform/wordpress/custom_directories.rb | 17 ++++++++++++++++- wpscan.gemspec | 2 +- 7 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 spec/fixtures/target/platform/wordpress/custom_directories/in_meta_content.html create mode 100644 spec/fixtures/target/platform/wordpress/custom_directories/scope.html create mode 100644 spec/fixtures/target/platform/wordpress/custom_directories/scope_meta_content.html diff --git a/lib/wpscan/target/platform/wordpress/custom_directories.rb b/lib/wpscan/target/platform/wordpress/custom_directories.rb index 34d044da..85046713 100644 --- a/lib/wpscan/target/platform/wordpress/custom_directories.rb +++ b/lib/wpscan/target/platform/wordpress/custom_directories.rb @@ -17,14 +17,15 @@ module WPScan # @return [ String ] The wp-content directory def content_dir(detection_mode = :mixed) unless @content_dir - escaped_url = Regexp.escape(url).gsub(/https?/i, 'https?') - pattern = %r{#{escaped_url}([\w\s\-\/]+)\/(?:themes|plugins|uploads|cache)\/}i + # #url_pattern is from CMSScanner::Target + pattern = %r{#{scope_url_pattern}([\w\s\-\/]+)\/(?:themes|plugins|uploads|cache)\/}i in_scope_urls(homepage_res) do |url| return @content_dir = Regexp.last_match[1] if url.match(pattern) end - xpath_pattern_from_page('//script[not(@src)]', pattern, homepage_res) do |match| + # Checks for the pattern in raw JS code, as well as @content attributes of meta tags + xpath_pattern_from_page('//script[not(@src)]|//meta/@content', pattern, homepage_res) do |match| return @content_dir = match[1] end @@ -96,14 +97,13 @@ module WPScan themes_uri.join("#{URI.encode(slug)}/").to_s end - # TODO: Factorise the code and the content_dir one ? # @return [ String, False ] String of the sub_dir found, false otherwise # @note: nil can not be returned here, otherwise if there is no sub_dir # the check would be done each time def sub_dir unless @sub_dir - escaped_url = Regexp.escape(url).gsub(/https?/i, 'https?') - pattern = %r{#{escaped_url}(.+?)\/(?:xmlrpc\.php|wp\-includes\/)}i + # escaped_url = Regexp.escape(url).gsub(/https?/i, 'https?') + pattern = %r{#{url_pattern}(.+?)\/(?:xmlrpc\.php|wp\-includes\/)}i in_scope_urls(homepage_res) do |url| return @sub_dir = Regexp.last_match[1] if url.match(pattern) diff --git a/spec/fixtures/target/platform/wordpress/custom_directories/in_meta_content.html b/spec/fixtures/target/platform/wordpress/custom_directories/in_meta_content.html new file mode 100644 index 00000000..28f84359 --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/custom_directories/in_meta_content.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/target/platform/wordpress/custom_directories/scope.html b/spec/fixtures/target/platform/wordpress/custom_directories/scope.html new file mode 100644 index 00000000..1542e213 --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/custom_directories/scope.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/target/platform/wordpress/custom_directories/scope_meta_content.html b/spec/fixtures/target/platform/wordpress/custom_directories/scope_meta_content.html new file mode 100644 index 00000000..beec3a61 --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/custom_directories/scope_meta_content.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/lib/target_spec.rb b/spec/lib/target_spec.rb index e03ef838..df79d600 100644 --- a/spec/lib/target_spec.rb +++ b/spec/lib/target_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true describe WPScan::Target do - subject(:target) { described_class.new(url) } + subject(:target) { described_class.new(url, opts) } let(:url) { 'http://ex.lo' } + let(:opts) { {} } it_behaves_like WPScan::Target::Platform::WordPress diff --git a/spec/shared_examples/target/platform/wordpress/custom_directories.rb b/spec/shared_examples/target/platform/wordpress/custom_directories.rb index 7d397155..7516a8b4 100644 --- a/spec/shared_examples/target/platform/wordpress/custom_directories.rb +++ b/spec/shared_examples/target/platform/wordpress/custom_directories.rb @@ -7,7 +7,8 @@ shared_examples 'WordPress::CustomDirectories' do { default: 'wp-content', https: 'wp-content', custom_w_spaces: 'custom content spaces', relative_one: 'wp-content', relative_two: 'wp-content', cache: 'wp-content', - in_raw_js: 'wp-content', with_sub_dir: 'app', relative_two_sub_dir: 'cms/wp-content' + in_raw_js: 'wp-content', with_sub_dir: 'app', relative_two_sub_dir: 'cms/wp-content', + in_meta_content: 'wp-content' }.each do |file, expected| it "returns #{expected} for #{file}.html" do stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{file}.html"))) @@ -16,6 +17,20 @@ shared_examples 'WordPress::CustomDirectories' do end end + context 'when scope given' do + let(:opts) { super().merge(scope: ['*.cloudfront.net']) } + + { + scope: 'wp-content', scope_meta_content: 'wp-content' + }.each do |file, expected| + it "returns #{expected} for #{file}.html" do + stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{file}.html"))) + + expect(target.content_dir).to eql expected + end + end + end + context 'when not found via the homepage' do before { stub_request(:get, target.url).to_return(body: '') } diff --git a/wpscan.gemspec b/wpscan.gemspec index c75a635e..6723f67d 100644 --- a/wpscan.gemspec +++ b/wpscan.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.executables = ['wpscan'] s.require_paths = ['lib'] - s.add_dependency 'cms_scanner', '~> 0.0.44.1' + s.add_dependency 'cms_scanner', '~> 0.0.44.2' s.add_development_dependency 'bundler', '>= 1.6' s.add_development_dependency 'coveralls', '~> 0.8.0'