cms_scanner 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +6 -0
  5. data/.travis.yml +14 -0
  6. data/Gemfile +6 -0
  7. data/README.md +20 -0
  8. data/Rakefile +9 -0
  9. data/app/app.rb +4 -0
  10. data/app/controllers.rb +2 -0
  11. data/app/controllers/core.rb +46 -0
  12. data/app/controllers/core/cli_options.rb +68 -0
  13. data/app/controllers/interesting_files.rb +12 -0
  14. data/app/finders.rb +1 -0
  15. data/app/finders/interesting_files.rb +21 -0
  16. data/app/finders/interesting_files/fantastico_fileslist.rb +23 -0
  17. data/app/finders/interesting_files/headers.rb +15 -0
  18. data/app/finders/interesting_files/robots_txt.rb +22 -0
  19. data/app/finders/interesting_files/search_replace_db_2.rb +28 -0
  20. data/app/finders/interesting_files/xml_rpc.rb +62 -0
  21. data/app/formatters.rb +3 -0
  22. data/app/formatters/cli.rb +18 -0
  23. data/app/formatters/cli_no_colour.rb +15 -0
  24. data/app/formatters/json.rb +12 -0
  25. data/app/models.rb +5 -0
  26. data/app/models/fantastico_fileslist.rb +20 -0
  27. data/app/models/headers.rb +37 -0
  28. data/app/models/interesting_file.rb +30 -0
  29. data/app/models/robots_txt.rb +20 -0
  30. data/app/models/xml_rpc.rb +35 -0
  31. data/app/views/cli/core/finished.erb +4 -0
  32. data/app/views/cli/core/started.erb +3 -0
  33. data/app/views/cli/interesting_files/findings.erb +19 -0
  34. data/app/views/cli/scan_aborted.erb +4 -0
  35. data/app/views/json/core/finished.erb +3 -0
  36. data/app/views/json/core/started.erb +3 -0
  37. data/app/views/json/interesting_files/findings.erb +1 -0
  38. data/app/views/json/scan_aborted.erb +4 -0
  39. data/cms_scanner.gemspec +37 -0
  40. data/examples/views/cli/wp_custom/test.erb +1 -0
  41. data/examples/views/json/wp_custom/test.erb +1 -0
  42. data/examples/wpscan.rb +29 -0
  43. data/lib/cms_scanner.rb +71 -0
  44. data/lib/cms_scanner/browser.rb +68 -0
  45. data/lib/cms_scanner/browser/actions.rb +48 -0
  46. data/lib/cms_scanner/browser/options.rb +53 -0
  47. data/lib/cms_scanner/cache/file_store.rb +75 -0
  48. data/lib/cms_scanner/cache/typhoeus.rb +21 -0
  49. data/lib/cms_scanner/controller.rb +90 -0
  50. data/lib/cms_scanner/controllers.rb +34 -0
  51. data/lib/cms_scanner/errors/auth_errors.rb +15 -0
  52. data/lib/cms_scanner/finders.rb +5 -0
  53. data/lib/cms_scanner/finders/finder.rb +27 -0
  54. data/lib/cms_scanner/finders/finding.rb +32 -0
  55. data/lib/cms_scanner/finders/findings.rb +25 -0
  56. data/lib/cms_scanner/finders/independent_finder.rb +30 -0
  57. data/lib/cms_scanner/finders/independent_finders.rb +41 -0
  58. data/lib/cms_scanner/formatter.rb +118 -0
  59. data/lib/cms_scanner/formatter/buffer.rb +15 -0
  60. data/lib/cms_scanner/target.rb +33 -0
  61. data/lib/cms_scanner/target/platform.rb +2 -0
  62. data/lib/cms_scanner/target/platform/php.rb +39 -0
  63. data/lib/cms_scanner/target/platform/wordpress.rb +35 -0
  64. data/lib/cms_scanner/target/platform/wordpress/custom_directories.rb +62 -0
  65. data/lib/cms_scanner/target/server.rb +3 -0
  66. data/lib/cms_scanner/target/server/apache.rb +43 -0
  67. data/lib/cms_scanner/target/server/generic.rb +34 -0
  68. data/lib/cms_scanner/target/server/iis.rb +48 -0
  69. data/lib/cms_scanner/version.rb +4 -0
  70. data/lib/cms_scanner/web_site.rb +68 -0
  71. data/lib/helper.rb +24 -0
  72. data/spec/app/controllers/core_spec.rb +152 -0
  73. data/spec/app/controllers/interesting_files_spec.rb +50 -0
  74. data/spec/app/finders/interesting_files/fantastico_fileslist_spec.rb +68 -0
  75. data/spec/app/finders/interesting_files/headers_spec.rb +38 -0
  76. data/spec/app/finders/interesting_files/robots_txt_spec.rb +56 -0
  77. data/spec/app/finders/interesting_files/search_replace_db_2_spec.rb +55 -0
  78. data/spec/app/finders/interesting_files/xml_rpc_spec.rb +138 -0
  79. data/spec/app/finders/interesting_files_spec.rb +13 -0
  80. data/spec/app/formatters/cli_no_colour_spec.rb +17 -0
  81. data/spec/app/formatters/cli_spec.rb +21 -0
  82. data/spec/app/formatters/json_spec.rb +33 -0
  83. data/spec/app/models/fantastico_fileslist_spec.rb +32 -0
  84. data/spec/app/models/headers_spec.rb +52 -0
  85. data/spec/app/models/interesting_file_spec.rb +51 -0
  86. data/spec/app/models/robots_txt_spec.rb +28 -0
  87. data/spec/app/models/xml_rpc_spec.rb +47 -0
  88. data/spec/cache/.gitignore +4 -0
  89. data/spec/dummy_finders.rb +41 -0
  90. data/spec/fixtures/interesting_files/fantastico_fileslist/fantastico_fileslist.txt +12 -0
  91. data/spec/fixtures/interesting_files/file.txt +4 -0
  92. data/spec/fixtures/interesting_files/headers/interesting.txt +14 -0
  93. data/spec/fixtures/interesting_files/headers/no_interesting.txt +12 -0
  94. data/spec/fixtures/interesting_files/robots_txt/robots.txt +10 -0
  95. data/spec/fixtures/interesting_files/search_replace_db_2/searchreplacedb2.php +188 -0
  96. data/spec/fixtures/interesting_files/xml_rpc/homepage_in_scope_pingback.html +7 -0
  97. data/spec/fixtures/interesting_files/xml_rpc/homepage_out_of_scope_pingback.html +7 -0
  98. data/spec/fixtures/interesting_files/xml_rpc/xmlrpc.php +1 -0
  99. data/spec/fixtures/output.txt +0 -0
  100. data/spec/fixtures/target/platform/php/debug_log/debug.log +2 -0
  101. data/spec/fixtures/target/platform/php/fpd/wp_rss_functions.php +2 -0
  102. data/spec/fixtures/target/platform/wordpress/custom_directories/custom_w_spaces.html +10 -0
  103. data/spec/fixtures/target/platform/wordpress/custom_directories/default.html +14 -0
  104. data/spec/fixtures/target/platform/wordpress/custom_directories/https.html +12 -0
  105. data/spec/fixtures/target/platform/wordpress/detection/default.html +4 -0
  106. data/spec/fixtures/target/platform/wordpress/detection/not_wp.html +8 -0
  107. data/spec/fixtures/target/platform/wordpress/detection/wp_includes.html +3 -0
  108. data/spec/fixtures/target/server/apache/directory_listing/2.2.16.html +15 -0
  109. data/spec/fixtures/target/server/generic/server/apache/basic.txt +5 -0
  110. data/spec/fixtures/target/server/generic/server/iis/basic.txt +6 -0
  111. data/spec/fixtures/target/server/generic/server/not_detected.txt +3 -0
  112. data/spec/fixtures/target/server/iis/directory_listing/no_parent.html +3 -0
  113. data/spec/fixtures/target/server/iis/directory_listing/with_parent.html +3 -0
  114. data/spec/fixtures/views/base/ctrl/local.erb +1 -0
  115. data/spec/fixtures/views/base/ctrl/test.erb +3 -0
  116. data/spec/fixtures/views/base/global.erb +1 -0
  117. data/spec/fixtures/views/base/test.erb +2 -0
  118. data/spec/fixtures/views/based_format/test.erb +1 -0
  119. data/spec/fixtures/views/json/render_me.erb +4 -0
  120. data/spec/lib/browser_spec.rb +141 -0
  121. data/spec/lib/cache/file_store_spec.rb +101 -0
  122. data/spec/lib/cache/typhoeus_spec.rb +30 -0
  123. data/spec/lib/cms_scanner_spec.rb +45 -0
  124. data/spec/lib/controller_spec.rb +23 -0
  125. data/spec/lib/controllers_spec.rb +52 -0
  126. data/spec/lib/finders/findings_spec.rb +49 -0
  127. data/spec/lib/finders/independent_finders_spec.rb +98 -0
  128. data/spec/lib/formatter_spec.rb +136 -0
  129. data/spec/lib/sub_scanner_spec.rb +27 -0
  130. data/spec/lib/target/platforms_spec.rb +13 -0
  131. data/spec/lib/target/servers_spec.rb +13 -0
  132. data/spec/lib/target_spec.rb +50 -0
  133. data/spec/lib/web_site_spec.rb +124 -0
  134. data/spec/shared_examples.rb +11 -0
  135. data/spec/shared_examples/browser_actions.rb +32 -0
  136. data/spec/shared_examples/finding.rb +20 -0
  137. data/spec/shared_examples/formatter_buffer.rb +8 -0
  138. data/spec/shared_examples/formatter_class_methods.rb +26 -0
  139. data/spec/shared_examples/independent_finder.rb +33 -0
  140. data/spec/shared_examples/target/platform/php.rb +58 -0
  141. data/spec/shared_examples/target/platform/wordpress.rb +41 -0
  142. data/spec/shared_examples/target/platform/wordpress/custom_directories.rb +50 -0
  143. data/spec/shared_examples/target/server/apache.rb +33 -0
  144. data/spec/shared_examples/target/server/generic.rb +34 -0
  145. data/spec/shared_examples/target/server/iis.rb +38 -0
  146. data/spec/spec_helper.rb +41 -0
  147. metadata +432 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f568051a37f6bcd75abe28d026dea5e2ff8a1372
4
+ data.tar.gz: d9399f063d4bc5b3929f566e2a018788dc708615
5
+ SHA512:
6
+ metadata.gz: 60523f8ef6495c41045f34e16bf18287f677b0c8749678d8cc9e4bfd4620b21ec357e06a9e230b6b83f3604d0cdfb24f159796a902939d1b9c239c7a5051fe7a
7
+ data.tar.gz: 38d4c48bf4e4b682732ce4f37b7eba45cca00c19b5edffbf89abd3a362bc8e782c10d842948a3fd657fa16737c09ceb7eb3461ed1551ebc795e2be5d0d3e8861
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --fail-fast
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ LineLength:
2
+ Max: 100
3
+ ClassVars:
4
+ Enabled: false
5
+ MethodLength:
6
+ Max: 15
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.0
5
+ - 2.1.1
6
+ - 2.1.2
7
+ - 2.1.3
8
+ - ruby-head
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: ruby-head
12
+ script:
13
+ - bundle exec rspec
14
+ - bundle exec rubocop
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :test do
5
+ gem 'coveralls', require: false
6
+ end
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # CMSScanner
2
+
3
+ [![Build Status](https://img.shields.io/travis/wpscanteam/CMSScanner.svg)](https://travis-ci.org/wpscanteam/CMSScanner)
4
+ [![Coverage Status](https://img.shields.io/coveralls/wpscanteam/CMSScanner.svg)](https://coveralls.io/r/wpscanteam/CMSScanner)
5
+ [![Code Climate](https://img.shields.io/codeclimate/github/wpscanteam/CMSScanner.svg)](https://codeclimate.com/github/wpscanteam/CMSScanner)
6
+ [![Dependency Status](https://img.shields.io/gemnasium/wpscanteam/CMSScanner.svg)](https://gemnasium.com/wpscanteam/CMSScanner)
7
+
8
+ The goal of this gem is to provide a quick and easy way to create a CMS/WebSite Scanner by acting like a Framework and providing classes, formatters etc.
9
+
10
+ ## /!\ This gem is currently Experimental /!\
11
+
12
+ Install Dependencies: ```bundle install```
13
+
14
+ ## Contributing
15
+
16
+ 1. Fork it ( https://github.com/wpscanteam/CMSScanner/fork )
17
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
18
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
19
+ 4. Push to the branch (`git push origin my-new-feature`)
20
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RuboCop::RakeTask.new
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ # Run rubocop & rspec before the build
9
+ task build: [:rubocop, :spec]
data/app/app.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative 'formatters'
2
+ require_relative 'controllers'
3
+ require_relative 'models'
4
+ require_relative 'finders'
@@ -0,0 +1,2 @@
1
+ require_relative 'controllers/core'
2
+ require_relative 'controllers/interesting_files'
@@ -0,0 +1,46 @@
1
+ require_relative 'core/cli_options'
2
+
3
+ module CMSScanner
4
+ module Controller
5
+ # Core Controller
6
+ class Core < Base
7
+ def setup_cache
8
+ return unless parsed_options[:cache_dir]
9
+
10
+ storage_path = File.join(parsed_options[:cache_dir], Digest::MD5.hexdigest(target.url))
11
+
12
+ Typhoeus::Config.cache = Cache::Typhoeus.new(storage_path)
13
+ Typhoeus::Config.cache.clean if parsed_options[:clear_cache]
14
+ end
15
+
16
+ def before_scan
17
+ setup_cache
18
+
19
+ fail "The url supplied '#{target.url}' seems to be down" unless target.online?
20
+
21
+ fail HTTPAuthRequiredError if target.http_auth?
22
+ fail ProxyAuthRequiredError if target.proxy_auth?
23
+
24
+ # TODO: ask if the redirection should be followed
25
+ # if user_interaction? is allowed (if followed, the Cache#storage_path should be updated)
26
+ redirection = target.redirection
27
+ fail "The url supplied redirects to #{redirection}" if redirection
28
+ end
29
+
30
+ def run
31
+ @start_time = Time.now
32
+ @start_memory = memory_usage
33
+
34
+ output('started', url: target.url)
35
+ end
36
+
37
+ def after_scan
38
+ @stop_time = Time.now
39
+ @elapsed = @stop_time - @start_time
40
+ @used_memory = memory_usage - @start_memory
41
+
42
+ output('finished')
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,68 @@
1
+ module CMSScanner
2
+ module Controller
3
+ # CLI Options for the Core Controller
4
+ class Core < Base
5
+ def cli_options
6
+ formats = NS::Formatter.availables
7
+
8
+ [
9
+ OptURL.new(['-u', '--url URL'], required: true),
10
+ OptBoolean.new(%w(-v --verbose)),
11
+ OptFilePath.new(['-o', '--output FILE', 'Output to FILE'], writable: true, exists: false),
12
+ OptChoice.new(['-f', '--format FORMAT',
13
+ "Available formats: #{formats.join(', ')}"], choices: formats),
14
+ OptChoice.new(['--detection-mode MODE', 'Modes: mixed (default), passive, aggressive'],
15
+ choices: %w(mixed passive aggressive),
16
+ normalize: :to_sym,
17
+ default: :mixed)
18
+ ] + cli_browser_options
19
+ end
20
+
21
+ # @return [ Array<OptParseValidator::OptBase> ]
22
+ def cli_browser_options
23
+ [
24
+ OptString.new(['--user-agent VALUE', '--ua']),
25
+ OptCredentials.new(['--http-auth login:password']),
26
+ OptPositiveInteger.new(['--max-threads VALUE', '-t', 'The max threads to use']),
27
+ OptPositiveInteger.new(['--request-timeout SECONDS', 'The request timeout in seconds']),
28
+ OptPositiveInteger.new(['--connect-timeout SECONDS',
29
+ 'The connection timeout in seconds'])
30
+ ] + cli_browser_proxy_options + cli_browser_cookies_options + cli_browser_cache_options
31
+ end
32
+
33
+ # @return [ Array<OptParseValidator::OptBase> ]
34
+ def cli_browser_proxy_options
35
+ [
36
+ OptProxy.new(['--proxy protocol://IP:port',
37
+ 'Supported protocols depend on the cURL installed']),
38
+ OptCredentials.new(['--proxy-auth login:password'])
39
+ ]
40
+ end
41
+
42
+ # @return [ Array<OptParseValidator::OptBase> ]
43
+ def cli_browser_cookies_options
44
+ [
45
+ OptString.new(['--cookie-string COOKIE',
46
+ 'Cookie string to use in requests, ' \
47
+ 'format: cookie1=value1[; cookie2=value2]']),
48
+ OptFilePath.new(['--cookie-jar FILE-PATH', 'File to read and write cookies'],
49
+ writable: true,
50
+ exists: false,
51
+ default: '/tmp/cms_scanner/cookie_jar.txt')
52
+ ]
53
+ end
54
+
55
+ # @return [ Array<OptParseValidator::OptBase> ]
56
+ def cli_browser_cache_options
57
+ [
58
+ OptInteger.new(['--cache-ttl TIME_TO_LIVE'], default: 600),
59
+ OptBoolean.new(['--clear-cache', 'Clear the cache before the scan']),
60
+ OptDirectoryPath.new(['--cache-dir PATH'],
61
+ readable: true,
62
+ writable: true,
63
+ default: '/tmp/cms_scanner/cache/')
64
+ ]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ module CMSScanner
2
+ module Controller
3
+ # InterestingFiles Controller
4
+ class InterestingFiles < Base
5
+ def run
6
+ findings = target.interesting_files(mode: parsed_options[:detection_mode])
7
+
8
+ output('findings', findings: findings) unless findings.empty?
9
+ end
10
+ end
11
+ end
12
+ end
data/app/finders.rb ADDED
@@ -0,0 +1 @@
1
+ require_relative 'finders/interesting_files'
@@ -0,0 +1,21 @@
1
+ require_relative 'interesting_files/headers'
2
+ require_relative 'interesting_files/robots_txt'
3
+ require_relative 'interesting_files/fantastico_fileslist'
4
+ require_relative 'interesting_files/search_replace_db_2'
5
+ require_relative 'interesting_files/xml_rpc'
6
+
7
+ module CMSScanner
8
+ module Finders
9
+ # Interesting Files Finder
10
+ class InterestingFiles
11
+ include IndependentFinder
12
+
13
+ # @param [ CMSScanner::Target ] target
14
+ def initialize(target)
15
+ %w(Headers RobotsTxt FantasticoFileslist SearchReplaceDB2 XMLRPC).each do |f|
16
+ finders << NS.const_get("Finders::InterestingFile::#{f}").new(target)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module CMSScanner
2
+ module Finders
3
+ module InterestingFile
4
+ # FantasticoFileslist finder
5
+ class FantasticoFileslist < Finder
6
+ # @return [ String ] The url of the fantastico_fileslist.txt file
7
+ def url
8
+ target.url('fantastico_fileslist.txt')
9
+ end
10
+
11
+ # @return [ InterestingFile ]
12
+ def aggressive(_opts = {})
13
+ res = NS::Browser.get(url)
14
+
15
+ return unless res && res.code == 200 && res.body.length > 0
16
+ return unless res.headers && res.headers['Content-Type'] =~ /\Atext\/plain/
17
+
18
+ NS::FantasticoFileslist.new(url, confidence: 100, found_by: found_by)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module CMSScanner
2
+ module Finders
3
+ module InterestingFile
4
+ # Interesting Headers finder
5
+ class Headers < Finder
6
+ # @return [ InterestingFile ]
7
+ def passive(_opts = {})
8
+ r = NS::Headers.new(target.url, confidence: 100, found_by: found_by)
9
+
10
+ r.interesting_entries.empty? ? nil : r
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module CMSScanner
2
+ module Finders
3
+ module InterestingFile
4
+ # Robots.txt finder
5
+ class RobotsTxt < Finder
6
+ # @return [ String ] The url of the robots.txt file
7
+ def url
8
+ target.url('robots.txt')
9
+ end
10
+
11
+ # @return [ InterestingFile ]
12
+ def aggressive(_opts = {})
13
+ res = NS::Browser.get(url)
14
+
15
+ return unless res && res.code == 200 && res.body =~ /(?:user-agent|(?:dis)?allow):/i
16
+
17
+ NS::RobotsTxt.new(url, confidence: 100, found_by: found_by)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module CMSScanner
2
+ module Finders
3
+ module InterestingFile
4
+ # SearchReplaceDB2 finder
5
+ class SearchReplaceDB2 < Finder
6
+ # @return [ String ] The url to the searchreplacedb2 PHP file
7
+ def url
8
+ target.url('searchreplacedb2.php')
9
+ end
10
+
11
+ # @return [ InterestingFile ]
12
+ def aggressive(_opts = {})
13
+ res = NS::Browser.get(url)
14
+
15
+ return unless res && res.code == 200 && res.body =~ /by interconnect/i
16
+
17
+ NS::InterestingFile.new(url, confidence: 100,
18
+ found_by: found_by,
19
+ references: references)
20
+ end
21
+
22
+ def references
23
+ %w(https://interconnectit.com/products/search-and-replace-for-wordpress-databases/)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ module CMSScanner
2
+ module Finders
3
+ module InterestingFile
4
+ # XML RPC finder
5
+ class XMLRPC < Finder
6
+ # @return [ Array<String> ] The potential urls to the XMl RPC file
7
+ def potential_urls
8
+ @potential_urls ||= []
9
+ end
10
+
11
+ # @return [ Array<XMLRPC> ]
12
+ def passive(opts = {})
13
+ [passive_headers(opts), passive_body(opts)].compact
14
+ end
15
+
16
+ # @return [ XMLRPC ]
17
+ def passive_headers(_opts = {})
18
+ url = NS::Browser.get(target.url).headers['X-Pingback']
19
+
20
+ return unless target.in_scope?(url)
21
+ potential_urls << url
22
+
23
+ NS::XMLRPC.new(url, confidence: 30, found_by: 'Headers (passive detection)')
24
+ end
25
+
26
+ # @return [ XMLRPC ]
27
+ def passive_body(_opts = {})
28
+ page = Nokogiri::HTML(NS::Browser.get(target.url).body)
29
+
30
+ page.css('link[rel="pingback"]').each do |tag|
31
+ url = tag.attribute('href').to_s
32
+
33
+ next unless target.in_scope?(url)
34
+ potential_urls << url
35
+
36
+ return NS::XMLRPC.new(url, confidence: 30,
37
+ found_by: 'Link Tag (passive detection)')
38
+ end
39
+ nil
40
+ end
41
+
42
+ # @return [ XMLRPC ]
43
+ def aggressive(_opts = {})
44
+ potential_urls << target.url('xmlrpc.php')
45
+
46
+ potential_urls.uniq.each do |potential_url|
47
+ next unless target.in_scope?(potential_url)
48
+
49
+ res = NS::Browser.get(potential_url)
50
+
51
+ next unless res && res.body =~ /XML-RPC server accepts POST requests only/i
52
+
53
+ return NS::XMLRPC.new(potential_url,
54
+ confidence: 100,
55
+ found_by: DIRECT_FILE_ACCESS)
56
+ end
57
+ nil
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
data/app/formatters.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'formatters/cli'
2
+ require_relative 'formatters/cli_no_colour'
3
+ require_relative 'formatters/json'
@@ -0,0 +1,18 @@
1
+ module CMSScanner
2
+ module Formatter
3
+ # CLI Formatter
4
+ class Cli < Base
5
+ def red(text)
6
+ colorize(text, 31)
7
+ end
8
+
9
+ def green(text)
10
+ colorize(text, 32)
11
+ end
12
+
13
+ def colorize(text, color_code)
14
+ "\e[#{color_code}m#{text}\e[0m"
15
+ end
16
+ end
17
+ end
18
+ end