diff --git a/.gitignore b/.gitignore index 9932d837..c0cf4aea 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ doc/ # Old files from v2 cache/ data/ + +# Profiling reports +bin/memprof*.report diff --git a/app/finders/config_backups/known_filenames.rb b/app/finders/config_backups/known_filenames.rb index deace44f..50b68e20 100644 --- a/app/finders/config_backups/known_filenames.rb +++ b/app/finders/config_backups/known_filenames.rb @@ -5,7 +5,7 @@ module WPScan module ConfigBackups # Config Backup finder class KnownFilenames < CMSScanner::Finders::Finder - include CMSScanner::Finders::Finder::Enumerator + include Finders::Finder::Enumerator # @param [ Hash ] opts # @option opts [ String ] :list @@ -16,17 +16,20 @@ module WPScan found = [] enumerate(potential_urls(opts), opts) do |res| - # Might need to improve that - next unless res.body =~ /define/i && res.body !~ /<\s?html/i - - found << Model::ConfigBackup.new(res.request.url, - found_by: DIRECT_ACCESS, - confidence: 100) + found << Model::ConfigBackup.new(res.request.url, found_by: DIRECT_ACCESS, confidence: 100) end found end + def valid_response?(res, _exclude_content = nil) + return unless res.code == 200 + + full_res = Browser.get(res.effective_url) + + full_res.body =~ /define/i && full_res.body !~ /<\s?html/i + end + # @param [ Hash ] opts # @option opts [ String ] :list Mandatory # diff --git a/app/finders/db_exports/known_locations.rb b/app/finders/db_exports/known_locations.rb index 6da23395..886cef3d 100644 --- a/app/finders/db_exports/known_locations.rb +++ b/app/finders/db_exports/known_locations.rb @@ -6,7 +6,9 @@ module WPScan # DB Exports finder # See https://github.com/wpscanteam/wpscan-v3/issues/62 class KnownLocations < CMSScanner::Finders::Finder - include CMSScanner::Finders::Finder::Enumerator + include Finders::Finder::Enumerator + + SQL_PATTERN = /(?:DROP|(?:UN)?LOCK|CREATE) TABLE|INSERT INTO/.freeze # @param [ Hash ] opts # @option opts [ String ] :list @@ -17,16 +19,21 @@ module WPScan found = [] enumerate(potential_urls(opts), opts) do |res| - next unless res.code == 200 && res.body =~ /INSERT INTO/ - - found << Model::DbExport.new(res.request.url, - found_by: DIRECT_ACCESS, - confidence: 100) + found << Model::DbExport.new(res.request.url, found_by: DIRECT_ACCESS, confidence: 100) end found end + def valid_response?(res, _exclude_content = nil) + return false unless res.code == 200 + + return true if res.effective_url.end_with?('.zip') && + res.headers['Content-Type'] =~ %r{\Aapplication/zip}i + + Browser.get(res.effective_url, headers: { 'Range' => 'bytes=0-3000' }).body =~ SQL_PATTERN ? true : false + end + # @param [ Hash ] opts # @option opts [ String ] :list Mandatory # diff --git a/app/finders/interesting_findings/tmm_db_migrate.rb b/app/finders/interesting_findings/tmm_db_migrate.rb index c1008dda..cc309db1 100644 --- a/app/finders/interesting_findings/tmm_db_migrate.rb +++ b/app/finders/interesting_findings/tmm_db_migrate.rb @@ -9,7 +9,7 @@ module WPScan def aggressive(_opts = {}) path = 'wp-content/uploads/tmm_db_migrate/tmm_db_migrate.zip' url = target.url(path) - res = Browser.get(url) + res = browser.forge_request(url, target.head_or_get_request_params).run return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i diff --git a/app/finders/interesting_findings/upload_sql_dump.rb b/app/finders/interesting_findings/upload_sql_dump.rb index 94a1d2cd..19185d8a 100644 --- a/app/finders/interesting_findings/upload_sql_dump.rb +++ b/app/finders/interesting_findings/upload_sql_dump.rb @@ -5,24 +5,25 @@ module WPScan module InterestingFindings # UploadSQLDump finder class UploadSQLDump < CMSScanner::Finders::Finder - SQL_PATTERN = /(?:(?:(?:DROP|CREATE) TABLE)|INSERT INTO)/.freeze + SQL_PATTERN = /(?:DROP|CREATE|(?:UN)?LOCK) TABLE|INSERT INTO/.freeze # @return [ InterestingFinding ] def aggressive(_opts = {}) - url = dump_url - res = Browser.get(url) + head_res = browser.forge_request(dump_url, target.head_or_get_request_params).run - return unless res.code == 200 && res.body =~ SQL_PATTERN + return unless head_res.code == 200 + + return unless Browser.get(dump_url, headers: { 'Range' => 'bytes=0-3000' }).body =~ SQL_PATTERN Model::UploadSQLDump.new( - url, + dump_url, confidence: 100, found_by: DIRECT_ACCESS ) end def dump_url - target.url('wp-content/uploads/dump.sql') + @dump_url ||= target.url('wp-content/uploads/dump.sql') end end end diff --git a/app/finders/timthumbs/known_locations.rb b/app/finders/timthumbs/known_locations.rb index ba995157..1d40075e 100644 --- a/app/finders/timthumbs/known_locations.rb +++ b/app/finders/timthumbs/known_locations.rb @@ -24,15 +24,13 @@ module WPScan end # @param [ Typhoeus::Response ] res - # @param [ Regexp,nil ] exclude_content + # @param [ Regexp, nil ] exclude_content # # @return [ Boolean ] def valid_response?(res, _exclude_content = nil) return false unless res.code == 400 - full_res = Browser.get(res.effective_url, cache_ttl: 0) - - full_res.body =~ /no image specified/i ? true : false + Browser.get(res.effective_url).body =~ /no image specified/i ? true : false end # @param [ Hash ] opts diff --git a/app/finders/users/rss_generator.rb b/app/finders/users/rss_generator.rb index 1ee05361..062cc432 100644 --- a/app/finders/users/rss_generator.rb +++ b/app/finders/users/rss_generator.rb @@ -19,20 +19,20 @@ module WPScan begin res.xml.xpath('//item/dc:creator').each do |node| - potential_username = node.text.to_s + username = node.text.to_s # Ignoring potential username longer than 60 characters and containing accents # as they are considered invalid. See https://github.com/wpscanteam/wpscan/issues/1215 - next if potential_username.length > 60 || potential_username =~ /[^\x00-\x7F]/ + next if username.strip.empty? || username.length > 60 || username =~ /[^\x00-\x7F]/ - potential_usernames << potential_username + potential_usernames << username end rescue Nokogiri::XML::XPath::SyntaxError next end - potential_usernames.uniq.each do |potential_username| - found << Model::User.new(potential_username, found_by: found_by, confidence: 50) + potential_usernames.uniq.each do |username| + found << Model::User.new(username, found_by: found_by, confidence: 50) end break diff --git a/app/finders/users/wp_json_api.rb b/app/finders/users/wp_json_api.rb index 4affa32c..aa6af0b7 100644 --- a/app/finders/users/wp_json_api.rb +++ b/app/finders/users/wp_json_api.rb @@ -55,7 +55,15 @@ module WPScan # @return [ String ] The URL of the API listing the Users def api_url - @api_url ||= target.url('wp-json/wp/v2/users/') + return @api_url if @api_url + + target.in_scope_urls(target.homepage_res, "//link[@rel='https://api.w.org/']/@href").each do |url, _tag| + uri = Addressable::URI.parse(url.strip) + + return @api_url = uri.join('wp/v2/users/').to_s if uri.path.include?('wp-json') + end + + @api_url = target.url('wp-json/wp/v2/users/') end end end diff --git a/app/models/wp_version.rb b/app/models/wp_version.rb index 3cca1df3..94e12bda 100644 --- a/app/models/wp_version.rb +++ b/app/models/wp_version.rb @@ -26,13 +26,12 @@ module WPScan @all_numbers = [] DB::Fingerprints.wp_fingerprints.each_value do |fp| - fp.each_value do |versions| - versions.each do |version| - @all_numbers << version unless @all_numbers.include?(version) - end - end + @all_numbers << fp.values end + # @all_numbers.flatten.uniq.sort! {} doesn't produce the same result here. + @all_numbers.flatten! + @all_numbers.uniq! @all_numbers.sort! { |a, b| Gem::Version.new(b) <=> Gem::Version.new(a) } end diff --git a/bin/wpscan-memprof b/bin/wpscan-memprof new file mode 100755 index 00000000..2397ce7e --- /dev/null +++ b/bin/wpscan-memprof @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +require 'memory_profiler' # https://github.com/SamSaffron/memory_profiler +require 'wpscan' + +report = MemoryProfiler.report(top: 15) do + WPScan::Scan.new do |s| + s.controllers << + WPScan::Controller::CustomDirectories.new << + WPScan::Controller::InterestingFindings.new << + WPScan::Controller::WpVersion.new << + WPScan::Controller::MainTheme.new << + WPScan::Controller::Enumeration.new << + WPScan::Controller::PasswordAttack.new << + WPScan::Controller::Aliases.new + + s.run + end +end + +report.pretty_print(scale_bytes: true, to_file: 'memprof.report') diff --git a/bin/wpscan-stackprof b/bin/wpscan-stackprof new file mode 100755 index 00000000..8e25adc6 --- /dev/null +++ b/bin/wpscan-stackprof @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby + +require 'stackprof' # https://github.com/tmm1/stackprof +require 'wpscan' + +# The object mode produces a segfault currently: https://github.com/jfelchner/ruby-progressbar/issues/153 +# StackProf.run(mode: :object, out: '/tmp/stackprof-object.dump') do +# StackProf.run(mode: :wall, out: '/tmp/stackprof-wall.dump') do +StackProf.run(mode: :cpu, out: '/tmp/stackprof-cpu.dump', interval: 500) do + # Couldn't we just load the ./wpscan here ? + # require_relative 'wpscan' doesn't work + WPScan::Scan.new do |s| + s.controllers << + WPScan::Controller::CustomDirectories.new << + WPScan::Controller::InterestingFindings.new << + WPScan::Controller::WpVersion.new << + WPScan::Controller::MainTheme.new << + WPScan::Controller::Enumeration.new << + WPScan::Controller::PasswordAttack.new << + WPScan::Controller::Aliases.new + + s.run + end +end diff --git a/lib/wpscan/db/dynamic_finders/plugin.rb b/lib/wpscan/db/dynamic_finders/plugin.rb index 9aaf8379..2e5671b2 100644 --- a/lib/wpscan/db/dynamic_finders/plugin.rb +++ b/lib/wpscan/db/dynamic_finders/plugin.rb @@ -62,7 +62,7 @@ module WPScan # @param [ String ] slug # @return [ Constant ] - def self.maybe_create_modudle(slug) + def self.maybe_create_module(slug) # What about slugs such as js_composer which will be done as JsComposer, just like js-composer constant_name = classify_slug(slug) @@ -75,10 +75,7 @@ module WPScan def self.create_versions_finders versions_finders_configs.each do |slug, finders| - # Kind of an issue here, module is created even if there is no valid classes - # Could put the #maybe_ directly in the #send() BUT it would be checked everytime, - # which is kind of a waste - mod = maybe_create_modudle(slug) + mod = maybe_create_module(slug) finders.each do |finder_class, config| klass = config['class'] || finder_class diff --git a/lib/wpscan/finders.rb b/lib/wpscan/finders.rb index 224920bd..f3a20fb2 100644 --- a/lib/wpscan/finders.rb +++ b/lib/wpscan/finders.rb @@ -41,9 +41,6 @@ module WPScan # # @yield [ Typhoeus::Response, String ] def enumerate(urls, opts = {}) - determine_request_params(urls, opts) - # determine_valid_response_codes(opts) - create_progress_bar(opts.merge(total: urls.size)) urls.each do |url, slug| @@ -61,6 +58,11 @@ module WPScan hydra.run end + # @return [ Hash ] + def request_params + @request_params ||= target.head_or_get_request_params.merge(cache_ttl: 0) + end + # @param [ Typhoeus::Response ] res # @param [ Regexp,nil ] exclude_content # @@ -73,7 +75,9 @@ module WPScan # Perform a full get to check if homepage or custom 404 if res.code == 200 - full_res = Browser.get(res.effective_url, cache_ttl: 0) + # The cache is not disabled to avoid additional request/s when checking + # for directory listing + full_res = Browser.get(res.effective_url) return false if target.homepage_or_404?(full_res) || exclude_content && full_res.body.match(exclude_content) @@ -83,23 +87,6 @@ module WPScan end # rubocop:enable Metrics/PerceivedComplexity - # @return [ Hash ] - def request_params - @request_params ||= { cache_ttl: 0 } - end - - # @param [ Hash ] urls - # @param [ Hash ] opts - def determine_request_params(urls, _opts) - head_res = Browser.head(urls.first[0], cache_ttl: 0) - - @request_params = if head_res.code == 405 - { method: :get, maxfilesize: 1, cache_ttl: 0 } - else - { method: :head, cache_ttl: 0 } - end - end - # @return [ Array ] def valid_response_codes @valid_response_codes ||= [200, 401, 403, 301] diff --git a/lib/wpscan/target.rb b/lib/wpscan/target.rb index 61e4ae66..0a8455f0 100644 --- a/lib/wpscan/target.rb +++ b/lib/wpscan/target.rb @@ -7,6 +7,15 @@ module WPScan class Target < CMSScanner::Target include Platform::WordPress + # @return [ Hash ] + def head_or_get_request_params + @head_or_get_request_params ||= if Browser.head(url).code == 405 + { method: :get, maxfilesize: 1 } + else + { method: :head } + end + end + # @return [ Boolean ] def vulnerable? [@wp_version, @main_theme, @plugins, @themes, @timthumbs].each do |e| diff --git a/lib/wpscan/target/platform/wordpress/custom_directories.rb b/lib/wpscan/target/platform/wordpress/custom_directories.rb index 3db8231a..c653b609 100644 --- a/lib/wpscan/target/platform/wordpress/custom_directories.rb +++ b/lib/wpscan/target/platform/wordpress/custom_directories.rb @@ -17,7 +17,7 @@ module WPScan def content_dir unless @content_dir escaped_url = Regexp.escape(url).gsub(/https?/i, 'https?') - pattern = %r{#{escaped_url}([^\/]+)\/(?:themes|plugins|uploads|cache)\/}i + pattern = %r{#{escaped_url}([\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) diff --git a/spec/app/finders/config_backups/known_filenames_spec.rb b/spec/app/finders/config_backups/known_filenames_spec.rb index 876f465f..9aa2c165 100644 --- a/spec/app/finders/config_backups/known_filenames_spec.rb +++ b/spec/app/finders/config_backups/known_filenames_spec.rb @@ -10,10 +10,10 @@ describe WPScan::Finders::ConfigBackups::KnownFilenames do describe '#aggressive' do before do expect(target).to receive(:sub_dir).at_least(1).and_return(false) - expect(target).to receive(:homepage_or_404?).at_least(1).and_return(false) + expect(target).to receive(:head_or_get_request_params).and_return(method: :head) finder.potential_urls(opts).each_key do |url| - stub_request(:get, url).to_return(status: 404) + stub_request(:head, url).to_return(status: 404) end end @@ -24,11 +24,12 @@ describe WPScan::Finders::ConfigBackups::KnownFilenames do end context 'when some files exist' do - let(:files) { ['%23wp-config.php%23', 'wp-config.bak'] } + let(:found_files) { ['%23wp-config.php%23', 'wp-config.bak'] } let(:config_backup) { File.read(fixtures.join('wp-config.php')) } before do - files.each do |file| + found_files.each do |file| + stub_request(:head, "#{url}#{file}").to_return(status: 200) stub_request(:get, "#{url}#{file}").to_return(body: config_backup) end end @@ -36,7 +37,7 @@ describe WPScan::Finders::ConfigBackups::KnownFilenames do it 'returns the expected Array' do expected = [] - files.each do |file| + found_files.each do |file| url = "#{target.url}#{file}" expected << WPScan::Model::ConfigBackup.new( url, diff --git a/spec/app/finders/db_exports/known_locations_spec.rb b/spec/app/finders/db_exports/known_locations_spec.rb index 48979864..407aa687 100644 --- a/spec/app/finders/db_exports/known_locations_spec.rb +++ b/spec/app/finders/db_exports/known_locations_spec.rb @@ -27,10 +27,10 @@ describe WPScan::Finders::DbExports::KnownLocations do describe '#aggressive' do before do expect(target).to receive(:sub_dir).at_least(1).and_return(false) - expect(target).to receive(:homepage_or_404?).at_least(1).and_return(false) + expect(target).to receive(:head_or_get_request_params).and_return(method: :head) finder.potential_urls(opts).each_key do |url| - stub_request(:get, url).to_return(status: 404) + stub_request(:head, url).to_return(status: 404) end end @@ -40,20 +40,28 @@ describe WPScan::Finders::DbExports::KnownLocations do end end + context 'when a zip returns a 200' do + xit + end + context 'when some files exist' do - let(:files) { %w[ex.sql backups/db_backup.sql] } + let(:found_files) { %w[ex.sql backups/db_backup.sql] } let(:db_export) { File.read(fixtures.join('dump.sql')) } before do - files.each do |file| - stub_request(:get, "#{url}#{file}").to_return(body: db_export) + found_files.each do |file| + stub_request(:head, "#{url}#{file}").to_return(status: 200) + + stub_request(:get, "#{url}#{file}") + .with(headers: { 'Range' => 'bytes=0-3000' }) + .to_return(body: db_export) end end it 'returns the expected Array' do expected = [] - files.each do |file| + found_files.each do |file| url = "#{target.url}#{file}" expected << WPScan::Model::DbExport.new( url, diff --git a/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb b/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb index a3316151..3916f58a 100644 --- a/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb +++ b/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb @@ -8,13 +8,16 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do let(:wp_content) { 'wp-content' } describe '#aggressive' do - before { expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) } + before do + expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) + expect(target).to receive(:head_or_get_request_params).and_return(method: :head) + end - after { expect(finder.aggressive).to eql @expected } + after { expect(finder.aggressive).to eql @expected } context 'when not a 200' do it 'returns nil' do - stub_request(:get, finder.dump_url).to_return(status: 404) + stub_request(:head, finder.dump_url).to_return(status: 404) @expected = nil end @@ -22,8 +25,11 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do context 'when a 200' do before do + stub_request(:head, finder.dump_url).to_return(status: 200) + stub_request(:get, finder.dump_url) - .to_return(status: 200, body: File.read(fixtures.join(fixture))) + .with(headers: { 'Range' => 'bytes=0-3000' }) + .to_return(body: File.read(fixtures.join(fixture))) end context 'when the body does not match a SQL dump' do diff --git a/spec/app/finders/users/wp_json_api_spec.rb b/spec/app/finders/users/wp_json_api_spec.rb index b3c00838..e24af419 100644 --- a/spec/app/finders/users/wp_json_api_spec.rb +++ b/spec/app/finders/users/wp_json_api_spec.rb @@ -7,7 +7,10 @@ describe WPScan::Finders::Users::WpJsonApi do let(:fixtures) { FINDERS_FIXTURES.join('users', 'wp_json_api') } describe '#aggressive' do - before { allow(target).to receive(:sub_dir).and_return(false) } + before do + allow(target).to receive(:sub_dir).and_return(false) + allow(finder).to receive(:api_url).and_return(target.url('wp-json/wp/v2/users/')) + end context 'when only one page of results' do before do @@ -80,4 +83,54 @@ describe WPScan::Finders::Users::WpJsonApi do end end end + + describe '#api_url' do + let(:fixtures) { super().join('api_url') } + + context 'when url in the homepage' do + { + in_scope: 'https://wp.lab/wp-json/wp/v2/users/', + out_of_scope: 'http://wp.lab/wp-json/wp/v2/users/' + }.each do |fixture, expected| + it "returns #{expected} for #{fixture}.html" do + stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{fixture}.html"))) + + expect(finder.api_url).to eql expected + end + end + + context 'when subdir' do + before { allow(target).to receive(:subdir).and_return('cms') } + + { + in_scope_subdir: 'https://wp.lab/cms/wp-json/wp/v2/users/', + in_scope_subdir_ignored: 'https://wp.lab/wp-json/wp/v2/users/' + }.each do |fixture, expected| + it "returns #{expected} for #{fixture}.html" do + stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{fixture}.html"))) + + expect(finder.api_url).to eql expected + end + end + end + end + + context 'when not in the homepage' do + before { stub_request(:get, target.url) } + + its(:api_url) { should eql target.url('wp-json/wp/v2/users/') } + end + + context 'when api_url already found' do + before { allow(target).to receive(:sub_dir).and_return(false) } + + it 'does not check the homepage again' do + url = target.url('wp-json/wp/v2/users/') + + finder.instance_variable_set(:@api_url, url) + + expect(finder.api_url).to eql url + end + end + end end diff --git a/spec/fixtures/finders/users/rss_generator/feed.xml b/spec/fixtures/finders/users/rss_generator/feed.xml index a9ab6453..46841668 100644 --- a/spec/fixtures/finders/users/rss_generator/feed.xml +++ b/spec/fixtures/finders/users/rss_generator/feed.xml @@ -59,5 +59,23 @@ Michael Schrage is a researcher at the MIT Sloan School of Management Initiative on the Digital Economy, where he does research and advisory work on how digital media transforms agency, human capital, and innovation.

]]>
+ + + Hello world! + http://ex.lo/2018/09/23/hello-world/ + http://ex.lo/2018/09/23/hello-world/#comments + Sun, 23 Sep 2018 11:31:56 +0000 + + + + + + Hello world! + http://ex.lo/2018/09/23/hello-world/ + http://ex.lo/2018/09/23/hello-world/#comments + Sun, 23 Sep 2018 11:31:56 +0000 + + + diff --git a/spec/fixtures/finders/users/wp_json_api/api_url/in_scope.html b/spec/fixtures/finders/users/wp_json_api/api_url/in_scope.html new file mode 100644 index 00000000..22c182e7 --- /dev/null +++ b/spec/fixtures/finders/users/wp_json_api/api_url/in_scope.html @@ -0,0 +1 @@ + diff --git a/spec/fixtures/finders/users/wp_json_api/api_url/in_scope_subdir.html b/spec/fixtures/finders/users/wp_json_api/api_url/in_scope_subdir.html new file mode 100644 index 00000000..71525fe0 --- /dev/null +++ b/spec/fixtures/finders/users/wp_json_api/api_url/in_scope_subdir.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/spec/fixtures/finders/users/wp_json_api/api_url/in_scope_subdir_ignored.html b/spec/fixtures/finders/users/wp_json_api/api_url/in_scope_subdir_ignored.html new file mode 100644 index 00000000..218372c8 --- /dev/null +++ b/spec/fixtures/finders/users/wp_json_api/api_url/in_scope_subdir_ignored.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/spec/fixtures/finders/users/wp_json_api/api_url/out_of_scope.html b/spec/fixtures/finders/users/wp_json_api/api_url/out_of_scope.html new file mode 100644 index 00000000..b793dc25 --- /dev/null +++ b/spec/fixtures/finders/users/wp_json_api/api_url/out_of_scope.html @@ -0,0 +1 @@ + diff --git a/spec/fixtures/target/platform/wordpress/custom_directories/relative_two_sub_dir.html b/spec/fixtures/target/platform/wordpress/custom_directories/relative_two_sub_dir.html new file mode 100644 index 00000000..872d5736 --- /dev/null +++ b/spec/fixtures/target/platform/wordpress/custom_directories/relative_two_sub_dir.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/spec/shared_examples/target/platform/wordpress/custom_directories.rb b/spec/shared_examples/target/platform/wordpress/custom_directories.rb index fad08e3b..942b9507 100644 --- a/spec/shared_examples/target/platform/wordpress/custom_directories.rb +++ b/spec/shared_examples/target/platform/wordpress/custom_directories.rb @@ -7,7 +7,7 @@ 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' + in_raw_js: 'wp-content', with_sub_dir: 'app', relative_two_sub_dir: 'cms/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"))) @@ -49,7 +49,7 @@ shared_examples 'WordPress::CustomDirectories' do end describe '#sub_dir' do - { default: false, with_sub_dir: 'wp' }.each do |file, expected| + { default: false, with_sub_dir: 'wp', relative_two_sub_dir: 'cms' }.each do |file, expected| it "returns #{expected} for #{file}.html" do fixture = File.join(fixtures, "#{file}.html") diff --git a/wpscan.gemspec b/wpscan.gemspec index 4c805188..14a5092d 100644 --- a/wpscan.gemspec +++ b/wpscan.gemspec @@ -25,10 +25,12 @@ Gem::Specification.new do |s| s.add_development_dependency 'bundler', '>= 1.6' s.add_development_dependency 'coveralls', '~> 0.8.0' + s.add_development_dependency 'memory_profiler', '~> 0.9.13' s.add_development_dependency 'rake', '~> 12.3' s.add_development_dependency 'rspec', '~> 3.8.0' s.add_development_dependency 'rspec-its', '~> 1.2.0' s.add_development_dependency 'rubocop', '~> 0.66.0' s.add_development_dependency 'simplecov', '~> 0.16.1' + s.add_development_dependency 'stackprof', '~> 0.2.12' s.add_development_dependency 'webmock', '~> 3.5.1' end