cms_scanner 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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') }