cms_scanner 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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