Class: CMSScanner::Target

Inherits:
WebSite
  • Object
show all
Includes:
Server::Generic
Defined in:
lib/cms_scanner/target.rb,
lib/cms_scanner/target/scope.rb,
lib/cms_scanner/target/hashes.rb,
lib/cms_scanner/target/server/iis.rb,
lib/cms_scanner/target/platform/php.rb,
lib/cms_scanner/target/server/nginx.rb,
lib/cms_scanner/target/server/apache.rb,
lib/cms_scanner/target/server/generic.rb

Overview

Scope system logic

Defined Under Namespace

Modules: Platform, Server Classes: Scope

Instance Attribute Summary

Attributes inherited from WebSite

#homepage_res, #opts, #uri

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Server::Generic

#directory_listing?, #directory_listing_entries, #headers, #server

Methods inherited from WebSite

#access_forbidden?, #homepage_url, #http_auth?, #online?, #proxy_auth?, #redirection, #url, #url=

Constructor Details

#initialize(url, opts = {}) ⇒ Target

Returns a new instance of Target.

Parameters:

  • url (String)
  • opts (Hash) (defaults to: {})

Options Hash (opts):



15
16
17
18
19
20
# File 'lib/cms_scanner/target.rb', line 15

def initialize(url, opts = {})
  super(url, opts)

  scope << uri.host
  [*opts[:scope]].each { |s| scope << s }
end

Class Method Details

.page_hash(page) ⇒ String

Note:

Comments are deleted to avoid cache generation details

Returns The md5sum of the page.

Parameters:

Returns:

  • (String)

    The md5sum of the page



9
10
11
12
13
14
15
16
17
18
# File 'lib/cms_scanner/target/hashes.rb', line 9

def self.page_hash(page)
  page = NS::Browser.get(page, followlocation: true) unless page.is_a?(Typhoeus::Response)

  # Removes comments and script tags before computing the hash
  # to remove any potential cached stuff
  html = Nokogiri::HTML(page.body)
  html.xpath('//script|//comment()').each(&:remove)

  Digest::MD5.hexdigest(html)
end

Instance Method Details

#comments_from_page(pattern, page = nil) {|MatchData, Nokogiri::XML::Comment| ... } ⇒ Array<Array<MatchData, Nokogiri::XML::Comment>>

Parameters:

Yields:

  • (MatchData, Nokogiri::XML::Comment)

Returns:

  • (Array<Array<MatchData, Nokogiri::XML::Comment>>)


64
65
66
67
68
# File 'lib/cms_scanner/target.rb', line 64

def comments_from_page(pattern, page = nil)
  xpath_pattern_from_page('//comment()', pattern, page) do |match, node|
    yield match, node if block_given?
  end
end

#error_404_hashString

Note:

This is used to detect potential custom 404 responding with a 200

Returns The hash of a 404.

Returns:

  • (String)

    The hash of a 404



27
28
29
# File 'lib/cms_scanner/target/hashes.rb', line 27

def error_404_hash
  @error404_hash ||= self.class.page_hash(non_existant_page_url)
end

#homepage_hashString

Returns The hash of the homepage.

Returns:

  • (String)

    The hash of the homepage



21
22
23
# File 'lib/cms_scanner/target/hashes.rb', line 21

def homepage_hash
  @homepage_hash ||= self.class.page_hash(url)
end

#homepage_or_404?(page) ⇒ Boolean

Returns Wether or not the page is a the homepage or a 404 based on its md5sum.

Parameters:

Returns:

  • (Boolean)

    Wether or not the page is a the homepage or a 404 based on its md5sum



38
39
40
41
42
# File 'lib/cms_scanner/target/hashes.rb', line 38

def homepage_or_404?(page)
  md5sum = self.class.page_hash(page)

  md5sum == homepage_hash || md5sum == error_404_hash
end

#in_scope?(url) ⇒ Boolean

Returns true if the url given is in scope.

Parameters:

  • url (String)

    An absolute URL

Returns:

  • (Boolean)

    true if the url given is in scope



12
13
14
15
16
# File 'lib/cms_scanner/target/scope.rb', line 12

def in_scope?(url)
  scope.include?(Addressable::URI.parse(url.strip).host)
rescue StandardError
  false
end

#in_scope_urls(res, xpath = '//link|//script|//style|//img|//a', attributes = %w[href src]) {|String, Nokogiri::XML::Element| ... } ⇒ Array<String>

Returns The in scope absolute URLs detected in the response’s body.

Parameters:

  • res (Typhoeus::Response)
  • xpath (String) (defaults to: '//link|//script|//style|//img|//a')
  • attributes (Array<String>) (defaults to: %w[href src])

Yields:

  • (String, Nokogiri::XML::Element)

    The in scope url and its associated tag

Returns:

  • (Array<String>)

    The in scope absolute URLs detected in the response’s body



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/cms_scanner/target/scope.rb', line 25

def in_scope_urls(res, xpath = '//link|//script|//style|//img|//a', attributes = %w[href src])
  found = []

  urls_from_page(res, xpath, attributes) do |url, tag|
    next unless in_scope?(url)

    yield url, tag if block_given?

    found << url
  end

  found
end

#interesting_findings(opts = {}) ⇒ Findings

Parameters:

  • opts (Hash) (defaults to: {})

Returns:

  • (Findings)


25
26
27
# File 'lib/cms_scanner/target.rb', line 25

def interesting_findings(opts = {})
  @interesting_findings ||= NS::Finders::InterestingFindings::Base.find(self, opts)
end

#javascripts_from_page(pattern, page = nil) {|MatchData, Nokogiri::XML::Element| ... } ⇒ Array<Array<MatchData, Nokogiri::XML::Element>>

Parameters:

Yields:

  • (MatchData, Nokogiri::XML::Element)

Returns:

  • (Array<Array<MatchData, Nokogiri::XML::Element>>)


75
76
77
78
79
# File 'lib/cms_scanner/target.rb', line 75

def javascripts_from_page(pattern, page = nil)
  xpath_pattern_from_page('//script', pattern, page) do |match, node|
    yield match, node if block_given?
  end
end

#non_existant_page_urlString

Returns The URL of an unlikely existant page.

Returns:

  • (String)

    The URL of an unlikely existant page



32
33
34
# File 'lib/cms_scanner/target/hashes.rb', line 32

def non_existant_page_url
  uri.join(Digest::MD5.hexdigest(rand(999_999_999).to_s) + '.html').to_s
end

#scopeArray<PublicSuffix::Domain, String>

Returns:



5
6
7
# File 'lib/cms_scanner/target/scope.rb', line 5

def scope
  @scope ||= Scope.new
end

#urls_from_page(page = nil, xpath = '//link|//script|//style|//img|//a', attributes = %w[href src]) {|String, Nokogiri::XML::Element| ... } ⇒ Array<String>

Returns The absolute URLs detected in the response’s body from the HTML tags.

Parameters:

  • page (Typhoeus::Response, String) (defaults to: nil)
  • xpath (String) (defaults to: '//link|//script|//style|//img|//a')
  • attributes (Array<String>) (defaults to: %w[href src])

Yields:

  • (String, Nokogiri::XML::Element)

    The url and its associated tag

Returns:

  • (Array<String>)

    The absolute URLs detected in the response’s body from the HTML tags



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/cms_scanner/target.rb', line 88

def urls_from_page(page = nil, xpath = '//link|//script|//style|//img|//a', attributes = %w[href src])
  page    = NS::Browser.get(url(page)) unless page.is_a?(Typhoeus::Response)
  found   = []

  page.html.xpath(xpath).each do |tag|
    attributes.each do |attribute|
      attr_value = tag[attribute]

      next unless attr_value && !attr_value.empty?

      tag_uri = begin
                  uri.join(attr_value.strip)
                rescue StandardError
                  # Skip potential malformed URLs etc.
                  next
                end

      tag_uri_string = tag_uri.to_s

      next unless tag_uri.host

      yield tag_uri_string, tag if block_given? && !found.include?(tag_uri_string)

      found << tag_uri_string
    end
  end

  found.uniq
end

#vulnerable?Boolean

Weteher or not vulnerabilities have been found. Used to set the exit code of the script and it should be overriden in the implementation

Returns:

  • (Boolean)


34
35
36
# File 'lib/cms_scanner/target.rb', line 34

def vulnerable?
  false
end

#xpath_pattern_from_page(xpath, pattern, page = nil) {|MatchData, Nokogiri::XML::Element| ... } ⇒ Array<Array<MatchData, Nokogiri::XML::Element>>

Parameters:

Yields:

  • (MatchData, Nokogiri::XML::Element)

Returns:

  • (Array<Array<MatchData, Nokogiri::XML::Element>>)


44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/cms_scanner/target.rb', line 44

def xpath_pattern_from_page(xpath, pattern, page = nil)
  page    = NS::Browser.get(url(page)) unless page.is_a?(Typhoeus::Response)
  matches = []

  page.html.xpath(xpath).each do |node|
    next unless node.text.strip =~ pattern

    yield Regexp.last_match, node if block_given?

    matches << [Regexp.last_match, node]
  end

  matches
end