cms_scanner 0.0.6 → 0.0.7

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/interesting_files/xml_rpc.rb +1 -3
  3. data/app/models.rb +1 -0
  4. data/app/models/interesting_file.rb +0 -4
  5. data/app/models/version.rb +17 -0
  6. data/app/views/cli/core/finished.erb +0 -1
  7. data/app/views/cli/interesting_files/findings.erb +1 -1
  8. data/cms_scanner.gemspec +2 -2
  9. data/lib/cms_scanner.rb +1 -0
  10. data/lib/cms_scanner/finders.rb +2 -0
  11. data/lib/cms_scanner/finders/finding.rb +4 -0
  12. data/lib/cms_scanner/finders/independent_finders.rb +1 -1
  13. data/lib/cms_scanner/finders/unique_finder.rb +17 -0
  14. data/lib/cms_scanner/finders/unique_finders.rb +39 -0
  15. data/lib/cms_scanner/target.rb +1 -0
  16. data/lib/cms_scanner/target/platform/wordpress.rb +2 -4
  17. data/lib/cms_scanner/target/platform/wordpress/custom_directories.rb +1 -2
  18. data/lib/cms_scanner/target/server/apache.rb +3 -2
  19. data/lib/cms_scanner/target/server/iis.rb +1 -2
  20. data/lib/cms_scanner/typhoeus/response.rb +9 -0
  21. data/lib/cms_scanner/version.rb +1 -1
  22. data/spec/app/controllers/core_spec.rb +0 -2
  23. data/spec/app/controllers/interesting_files_spec.rb +0 -2
  24. data/spec/app/finders/interesting_files/fantastico_fileslist_spec.rb +0 -2
  25. data/spec/app/finders/interesting_files/headers_spec.rb +0 -2
  26. data/spec/app/finders/interesting_files/robots_txt_spec.rb +0 -2
  27. data/spec/app/finders/interesting_files/search_replace_db_2_spec.rb +0 -2
  28. data/spec/app/finders/interesting_files/xml_rpc_spec.rb +0 -2
  29. data/spec/app/finders/interesting_files_spec.rb +1 -2
  30. data/spec/app/formatters/cli_no_colour_spec.rb +0 -2
  31. data/spec/app/formatters/cli_spec.rb +0 -2
  32. data/spec/app/formatters/json_spec.rb +0 -2
  33. data/spec/app/models/fantastico_fileslist_spec.rb +0 -1
  34. data/spec/app/models/headers_spec.rb +0 -1
  35. data/spec/app/models/interesting_file_spec.rb +0 -2
  36. data/spec/app/models/robots_txt_spec.rb +0 -1
  37. data/spec/app/models/version_spec.rb +23 -0
  38. data/spec/app/models/xml_rpc_spec.rb +0 -1
  39. data/spec/app/views_spec.rb +0 -2
  40. data/spec/dummy_finding.rb +21 -0
  41. data/spec/dummy_independent_finders.rb +25 -0
  42. data/spec/dummy_unique_finders.rb +32 -0
  43. data/spec/lib/browser_spec.rb +0 -1
  44. data/spec/lib/cache/file_store_spec.rb +0 -1
  45. data/spec/lib/cache/typhoeus_spec.rb +0 -2
  46. data/spec/lib/cms_scanner_spec.rb +0 -1
  47. data/spec/lib/controller_spec.rb +0 -2
  48. data/spec/lib/controllers_spec.rb +0 -2
  49. data/spec/lib/finders/findings_spec.rb +1 -3
  50. data/spec/lib/finders/independent_finders_spec.rb +4 -6
  51. data/spec/lib/finders/unique_finder_spec.rb +24 -0
  52. data/spec/lib/finders/unique_finders_spec.rb +133 -0
  53. data/spec/lib/formatter_spec.rb +0 -3
  54. data/spec/lib/target_spec.rb +0 -2
  55. data/spec/lib/web_site_spec.rb +0 -3
  56. data/spec/output/core/finished.cli_no_colour +0 -1
  57. data/spec/output/interesting_files/empty.cli_no_colour +1 -0
  58. data/spec/output/interesting_files/findings.cli_no_colour +1 -0
  59. data/spec/shared_examples/browser_actions.rb +0 -2
  60. data/spec/shared_examples/finding.rb +21 -1
  61. data/spec/shared_examples/formatter_buffer.rb +0 -2
  62. data/spec/shared_examples/independent_finder.rb +1 -3
  63. data/spec/shared_examples/target/platform/php.rb +0 -1
  64. data/spec/shared_examples/target/platform/wordpress.rb +0 -2
  65. data/spec/shared_examples/target/server/apache.rb +0 -1
  66. data/spec/shared_examples/target/server/generic.rb +0 -1
  67. data/spec/shared_examples/target/server/iis.rb +0 -1
  68. data/spec/shared_examples/views/core.rb +0 -1
  69. data/spec/shared_examples/views/interesting_files.rb +0 -1
  70. metadata +21 -7
  71. data/spec/dummy_finders.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4678e465b2b4eaf41a295ca51d5c8e19036cd608
4
- data.tar.gz: 4791201f53009021294db6cb8ebbf8a502fe996a
3
+ metadata.gz: 0866fc4bfc65ce2c0b92ac2b4d8b0e6d412f0f4e
4
+ data.tar.gz: d1a849df9cfb4d7e2efb41bf836b62df007e02b8
5
5
  SHA512:
6
- metadata.gz: aa604fb6779740c7a82aa02d435b8281ed80bd422cf843660803d1eb12e5544c5b96686c5234d41aad53b61cdf101d4cded4c4731595ca1db9745b16fb78d312
7
- data.tar.gz: 3fae9b03e48e97719cc01404a1cef60fc418b29137dd2cedf7892923a07ad243a69a3274b50758653f3ca676ad28d85fc69028d343a82145fa19b34b6053a519
6
+ metadata.gz: 6351f6c0f03e6c4a7983933c723a9f479cc1b9a39d5ff4683930f9bb91b1c6f9b4f087b0ffaa5e193c7fcbfb00bb41317884cd9da25d062d0df4604e416c8e15
7
+ data.tar.gz: 40fa45e9e46359b1f9b5c818ed470213fe7434c73fdbf93eeed173ea27c5c0f8a3ef589f7c61c510cb6c90ae7da19568947a2d571a5723695dadb32a3a5ed00d
@@ -25,9 +25,7 @@ module CMSScanner
25
25
 
26
26
  # @return [ XMLRPC ]
27
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|
28
+ NS::Browser.get(target.url).html.css('link[rel="pingback"]').each do |tag|
31
29
  url = tag.attribute('href').to_s
32
30
 
33
31
  next unless target.in_scope?(url)
data/app/models.rb CHANGED
@@ -3,3 +3,4 @@ require_relative 'models/robots_txt'
3
3
  require_relative 'models/fantastico_fileslist'
4
4
  require_relative 'models/headers'
5
5
  require_relative 'models/xml_rpc'
6
+ require_relative 'models/version'
@@ -22,9 +22,5 @@ module CMSScanner
22
22
  def ==(other)
23
23
  url == other.url
24
24
  end
25
-
26
- def eql?(other)
27
- url == other.url && confidence == other.confidence && found_by == other.found_by
28
- end
29
25
  end
30
26
  end
@@ -0,0 +1,17 @@
1
+ module CMSScanner
2
+ # Version
3
+ class Version
4
+ include NS::Finders::Finding
5
+
6
+ attr_reader :number
7
+
8
+ def initialize(number, opts = {})
9
+ @number = number
10
+ parse_finding_options(opts)
11
+ end
12
+
13
+ def ==(other)
14
+ number == other.number
15
+ end
16
+ end
17
+ end
@@ -1,4 +1,3 @@
1
-
2
1
  <%= green('[+]') %> Finished: <%= @stop_time.asctime %>
3
2
  <%= green('[+]') %> Memory used: <%= @used_memory.bytes_to_human %>
4
3
  <%= green('[+]') %> Elapsed time: <%= Time.at(@elapsed).utc.strftime('%H:%M:%S') %>
@@ -18,4 +18,4 @@ Interesting Findings: <%= @findings.size %>
18
18
  <% end -%>
19
19
  <%= render('_array', a: finding.references, s: 'Reference', p: 'References') -%>
20
20
  <%= render('_array', a: finding.interesting_entries, s: 'Interesting Entry', p: 'Interesting Entries') -%>
21
- <% end -%>
21
+ <% end %>
data/cms_scanner.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.version = CMSScanner::VERSION
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.required_ruby_version = '>= 2.0.0'
12
- s.authors = ['WPScanTeam - Erwan le Rousseau']
12
+ s.authors = ['WPScanTeam - Erwan Le Rousseau']
13
13
  s.email = ['erwan.lr@gmail.com']
14
14
  s.summary = 'Experimental CMSScanner'
15
15
  s.description = 'Experimental CMSScanner'
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
31
31
  s.add_development_dependency 'rspec', '~> 3.1'
32
32
  s.add_development_dependency 'rspec-its'
33
33
  s.add_development_dependency 'bundler', '~> 1.6'
34
- s.add_development_dependency 'rubocop', '~> 0.27'
34
+ s.add_development_dependency 'rubocop', '~> 0.28'
35
35
  s.add_development_dependency 'webmock', '>= 1.18'
36
36
  s.add_development_dependency 'simplecov', '~> 0.9'
37
37
  end
data/lib/cms_scanner.rb CHANGED
@@ -10,6 +10,7 @@ require 'fileutils'
10
10
  require 'pathname'
11
11
  # Custom Libs
12
12
  require 'helper'
13
+ require 'cms_scanner/typhoeus/response'
13
14
  require 'cms_scanner/errors/auth_errors'
14
15
  require 'cms_scanner/cache/typhoeus'
15
16
  require 'cms_scanner/target'
@@ -3,3 +3,5 @@ require 'cms_scanner/finders/finding'
3
3
  require 'cms_scanner/finders/findings'
4
4
  require 'cms_scanner/finders/independent_finders'
5
5
  require 'cms_scanner/finders/independent_finder'
6
+ require 'cms_scanner/finders/unique_finders'
7
+ require 'cms_scanner/finders/unique_finder'
@@ -32,6 +32,10 @@ module CMSScanner
32
32
  def parse_finding_options(opts = {})
33
33
  FINDING_OPTS.each { |opt| send("#{opt}=", opts[opt]) if opts.key?(opt) }
34
34
  end
35
+
36
+ def eql?(other)
37
+ self == other && confidence == other.confidence && found_by == other.found_by
38
+ end
35
39
  end
36
40
  end
37
41
  end
@@ -2,7 +2,7 @@ module CMSScanner
2
2
  module Finders
3
3
  # Independent Finders container
4
4
  # This class is designed to handle independent results
5
- # which are not related with others
5
+ # which are not related with each others
6
6
  # e.g: interesting files
7
7
  class IndependentFinders < Array
8
8
  # @return [ Findings ]
@@ -0,0 +1,17 @@
1
+ module CMSScanner
2
+ module Finders
3
+ # Unique Finder
4
+ module UniqueFinder
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ include IndependentFinder
8
+
9
+ # @return [ Array ]
10
+ def finders
11
+ @finders ||= NS::Finders::UniqueFinders.new
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ module CMSScanner
2
+ module Finders
3
+ # Unique Finders container
4
+ #
5
+ # This class is designed to return a unique result such as a version
6
+ # Note: Finders contained can return multiple results but the #run will only
7
+ # returned the best finding
8
+ class UniqueFinders < IndependentFinders
9
+ # @param [ Hash ] opts
10
+ # @option opts [ Symbol ] mode :mixed, :passive or :aggressive
11
+ # @option opts [ Int ] :confidence_threshold If a finding's confidence reaches this value,
12
+ # it will be returned as the best finding.
13
+ # Default is 100.
14
+ # If <= 0, all finders will be ran.
15
+ #
16
+ # @return [ Object ]
17
+ def run(opts = {})
18
+ opts[:confidence_threshold] ||= 100
19
+
20
+ symbols_from_mode(opts[:mode]).each do |symbol|
21
+ each do |finder|
22
+ [*finder.send(symbol, opts)].each do |found|
23
+ findings << found
24
+ end
25
+
26
+ next if opts[:confidence_threshold] <= 0
27
+
28
+ findings.each do |f|
29
+ return f if f.confidence >= opts[:confidence_threshold]
30
+ end
31
+ end
32
+ end
33
+
34
+ # results are sorted by confidence ASC
35
+ findings.sort_by(&:confidence).last
36
+ end
37
+ end
38
+ end
39
+ end
@@ -6,6 +6,7 @@ module CMSScanner
6
6
  # Target to Scan
7
7
  class Target < WebSite
8
8
  include Server::Generic
9
+
9
10
  # @note Subdomains are considered out of scope (maybe consider them in ?)
10
11
  # Also, // are handled by Addressable::URI, but worngly :/
11
12
  # e.g: Addressable::URI.parse('//file').host => file
@@ -9,12 +9,10 @@ module CMSScanner
9
9
  module WordPress
10
10
  include PHP
11
11
 
12
- WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|plugins|plugins))|wp-includes)/}i
12
+ WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|plugins|uploads))|wp-includes)/}i
13
13
 
14
14
  def wordpress?
15
- page = Nokogiri::HTML(Browser.get(url).body)
16
-
17
- page.css('script, link').each do |tag|
15
+ NS::Browser.get(url).html.css('script, link').each do |tag|
18
16
  tag_url = tag.attribute('href').to_s
19
17
 
20
18
  next unless in_scope?(tag_url)
@@ -14,11 +14,10 @@ module CMSScanner
14
14
  # @return [ String ] The wp-content directory
15
15
  def content_dir
16
16
  unless @content_dir
17
- page = Nokogiri::HTML(Browser.get(url).body)
18
17
  escaped_url = Regexp.escape(url).gsub(/https?/i, 'https?')
19
18
  pattern = %r{#{escaped_url}(.+?)\/(?:themes|plugins|uploads)\/}i
20
19
 
21
- page.css('link,script,style,img').each do |tag|
20
+ NS::Browser.get(url).html.css('link,script,style,img').each do |tag|
22
21
  %w(href src).each do |attribute|
23
22
  attr_value = tag.attribute(attribute).to_s
24
23
 
@@ -30,10 +30,11 @@ module CMSScanner
30
30
  def directory_listing_entries(path = nil, params = {})
31
31
  return [] unless directory_listing?(path, params)
32
32
 
33
- doc = Nokogiri::HTML(NS::Browser.get(url(path), params).body)
34
33
  found = []
35
34
 
36
- doc.css('td a').each { |node| found << node.text.to_s }
35
+ NS::Browser.get(url(path), params).html.css('td a').each do |node|
36
+ found << node.text.to_s
37
+ end
37
38
 
38
39
  found[1..-1] # returns the array w/o the first element 'Parent Directory'
39
40
  end
@@ -30,10 +30,9 @@ module CMSScanner
30
30
  def directory_listing_entries(path = nil, params = {})
31
31
  return [] unless directory_listing?(path, params)
32
32
 
33
- doc = Nokogiri::HTML(NS::Browser.get(url(path), params).body)
34
33
  found = []
35
34
 
36
- doc.css('pre a').each do |node|
35
+ NS::Browser.get(url(path), params).html.css('pre a').each do |node|
37
36
  entry = node.text.to_s
38
37
 
39
38
  next if entry == '[To Parent Directory]'
@@ -0,0 +1,9 @@
1
+ module Typhoeus
2
+ # Custom Response class
3
+ class Response
4
+ # @return [ Nokogiri::HTML ] The response's body parsed by Nokogiri
5
+ def html
6
+ Nokogiri::HTML(body)
7
+ end
8
+ end
9
+ end
@@ -1,4 +1,4 @@
1
1
  # Version
2
2
  module CMSScanner
3
- VERSION = '0.0.6'
3
+ VERSION = '0.0.7'
4
4
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Controller::Core do
4
-
5
4
  subject(:core) { described_class.new }
6
5
  let(:target_url) { 'http://example.com/' }
7
6
  let(:parsed_options) { { url: target_url } }
@@ -148,5 +147,4 @@ describe CMSScanner::Controller::Core do
148
147
  core.after_scan
149
148
  end
150
149
  end
151
-
152
150
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Controller::InterestingFiles do
4
-
5
4
  subject(:controller) { described_class.new }
6
5
  let(:target_url) { 'http://example.com/' }
7
6
  let(:parsed_options) { { url: target_url } }
@@ -46,5 +45,4 @@ describe CMSScanner::Controller::InterestingFiles do
46
45
  end
47
46
  end
48
47
  end
49
-
50
48
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Finders::InterestingFile::FantasticoFileslist do
4
-
5
4
  subject(:finder) { described_class.new(target) }
6
5
  let(:target) { CMSScanner::Target.new(url) }
7
6
  let(:url) { 'http://example.com/' }
@@ -64,5 +63,4 @@ describe CMSScanner::Finders::InterestingFile::FantasticoFileslist do
64
63
  end
65
64
  end
66
65
  end
67
-
68
66
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Finders::InterestingFile::Headers do
4
-
5
4
  subject(:finder) { described_class.new(target) }
6
5
  let(:target) { CMSScanner::Target.new(url) }
7
6
  let(:url) { 'http://example.com/' }
@@ -34,5 +33,4 @@ describe CMSScanner::Finders::InterestingFile::Headers do
34
33
  end
35
34
  end
36
35
  end
37
-
38
36
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Finders::InterestingFile::RobotsTxt do
4
-
5
4
  subject(:finder) { described_class.new(target) }
6
5
  let(:target) { CMSScanner::Target.new(url) }
7
6
  let(:url) { 'http://example.com/' }
@@ -52,5 +51,4 @@ describe CMSScanner::Finders::InterestingFile::RobotsTxt do
52
51
  end
53
52
  end
54
53
  end
55
-
56
54
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Finders::InterestingFile::SearchReplaceDB2 do
4
-
5
4
  subject(:finder) { described_class.new(target) }
6
5
  let(:target) { CMSScanner::Target.new(url) }
7
6
  let(:url) { 'http://example.com/' }
@@ -51,5 +50,4 @@ describe CMSScanner::Finders::InterestingFile::SearchReplaceDB2 do
51
50
  end
52
51
  end
53
52
  end
54
-
55
53
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Finders::InterestingFile::XMLRPC do
4
-
5
4
  subject(:finder) { described_class.new(target) }
6
5
  let(:target) { CMSScanner::Target.new(url) }
7
6
  let(:url) { 'http://ex.lo/' }
@@ -134,5 +133,4 @@ describe CMSScanner::Finders::InterestingFile::XMLRPC do
134
133
  end
135
134
  end
136
135
  end
137
-
138
136
  end
@@ -1,13 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Finders::InterestingFiles do
4
-
5
4
  it_behaves_like CMSScanner::Finders::IndependentFinder do
6
5
  let(:expected_finders) { %w(Headers RobotsTxt FantasticoFileslist SearchReplaceDB2 XMLRPC) }
6
+ let(:expected_finders_class) { CMSScanner::Finders::IndependentFinders }
7
7
  end
8
8
 
9
9
  subject(:files) { described_class.new(target) }
10
10
  let(:target) { CMSScanner::Target.new(url) }
11
11
  let(:url) { 'http://example.com/' }
12
-
13
12
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Formatter::CliNoColour do
4
-
5
4
  subject(:formatter) { described_class.new }
6
5
 
7
6
  describe '#format' do
@@ -13,5 +12,4 @@ describe CMSScanner::Formatter::CliNoColour do
13
12
  expect(formatter.red('Text')).to eq 'Text'
14
13
  end
15
14
  end
16
-
17
15
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Formatter::Cli do
4
-
5
4
  subject(:formatter) { described_class.new }
6
5
 
7
6
  describe '#format' do
@@ -17,5 +16,4 @@ describe CMSScanner::Formatter::Cli do
17
16
  expect(formatter.green('Another Text')).to eq "\e[32mAnother Text\e[0m"
18
17
  end
19
18
  end
20
-
21
19
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::Formatter::Json do
4
-
5
4
  it_behaves_like CMSScanner::Formatter::Buffer
6
5
 
7
6
  subject(:formatter) { described_class.new }
@@ -29,5 +28,4 @@ describe CMSScanner::Formatter::Json do
29
28
  formatter.beautify
30
29
  end
31
30
  end
32
-
33
31
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CMSScanner::FantasticoFileslist do
4
-
5
4
  subject(:file) { described_class.new(url) }
6
5
  let(:url) { 'http://example.com/robots.txt' }
7
6
  let(:fixtures) { File.join(FIXTURES, 'interesting_files', 'fantastico_fileslist') }