cms_scanner 0.0.41.10 → 0.0.42.0
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.
- checksums.yaml +4 -4
- data/app/app.rb +23 -4
- data/app/controllers/core.rb +8 -6
- data/app/controllers/core/cli_options.rb +2 -0
- data/app/controllers/interesting_findings.rb +2 -0
- data/app/finders/interesting_findings.rb +2 -0
- data/app/finders/interesting_findings/fantastico_fileslist.rb +6 -8
- data/app/finders/interesting_findings/headers.rb +3 -1
- data/app/finders/interesting_findings/robots_txt.rb +5 -7
- data/app/finders/interesting_findings/search_replace_db_2.rb +8 -10
- data/app/finders/interesting_findings/xml_rpc.rb +8 -6
- data/app/formatters/cli.rb +2 -0
- data/app/formatters/cli_no_color.rb +2 -0
- data/app/formatters/cli_no_colour.rb +2 -0
- data/app/formatters/json.rb +2 -0
- data/app/models/fantastico_fileslist.rb +16 -12
- data/app/models/headers.rb +29 -25
- data/app/models/interesting_finding.rb +44 -40
- data/app/models/robots_txt.rb +18 -14
- data/app/models/user.rb +25 -21
- data/app/models/version.rb +45 -41
- data/app/models/xml_rpc.rb +58 -54
- data/lib/cms_scanner.rb +5 -85
- data/lib/cms_scanner/browser.rb +2 -0
- data/lib/cms_scanner/browser/actions.rb +13 -13
- data/lib/cms_scanner/browser/options.rb +2 -0
- data/lib/cms_scanner/cache/file_store.rb +2 -0
- data/lib/cms_scanner/cache/typhoeus.rb +2 -0
- data/lib/cms_scanner/controller.rb +2 -0
- data/lib/cms_scanner/controllers.rb +3 -1
- data/lib/cms_scanner/errors.rb +11 -0
- data/lib/cms_scanner/errors/http.rb +52 -51
- data/lib/cms_scanner/errors/scan.rb +10 -6
- data/lib/cms_scanner/exit_code.rb +2 -0
- data/lib/cms_scanner/finders.rb +2 -0
- data/lib/cms_scanner/finders/base_finders.rb +2 -0
- data/lib/cms_scanner/finders/finder.rb +3 -1
- data/lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb +3 -1
- data/lib/cms_scanner/finders/finder/enumerator.rb +44 -15
- data/lib/cms_scanner/finders/finder/fingerprinter.rb +9 -21
- data/lib/cms_scanner/finders/finder/smart_url_checker.rb +2 -0
- data/lib/cms_scanner/finders/finder/smart_url_checker/findings.rb +2 -0
- data/lib/cms_scanner/finders/finding.rb +2 -0
- data/lib/cms_scanner/finders/findings.rb +2 -0
- data/lib/cms_scanner/finders/independent_finder.rb +2 -0
- data/lib/cms_scanner/finders/independent_finders.rb +2 -0
- data/lib/cms_scanner/finders/same_type_finder.rb +2 -0
- data/lib/cms_scanner/finders/same_type_finders.rb +2 -0
- data/lib/cms_scanner/finders/unique_finder.rb +2 -0
- data/lib/cms_scanner/finders/unique_finders.rb +2 -0
- data/lib/cms_scanner/formatter.rb +2 -0
- data/lib/cms_scanner/formatter/buffer.rb +3 -1
- data/lib/cms_scanner/helper.rb +2 -0
- data/lib/cms_scanner/numeric.rb +2 -0
- data/lib/cms_scanner/progressbar_null_output.rb +2 -0
- data/lib/cms_scanner/public_suffix/domain.rb +2 -0
- data/lib/cms_scanner/references.rb +2 -0
- data/lib/cms_scanner/scan.rb +86 -0
- data/lib/cms_scanner/target.rb +2 -0
- data/lib/cms_scanner/target/hashes.rb +2 -0
- data/lib/cms_scanner/target/platform.rb +2 -0
- data/lib/cms_scanner/target/platform/php.rb +4 -2
- data/lib/cms_scanner/target/scope.rb +2 -0
- data/lib/cms_scanner/target/server.rb +2 -0
- data/lib/cms_scanner/target/server/apache.rb +2 -0
- data/lib/cms_scanner/target/server/generic.rb +2 -0
- data/lib/cms_scanner/target/server/iis.rb +2 -0
- data/lib/cms_scanner/target/server/nginx.rb +2 -0
- data/lib/cms_scanner/typhoeus/hydra.rb +2 -0
- data/lib/cms_scanner/typhoeus/response.rb +2 -0
- data/lib/cms_scanner/version.rb +3 -1
- data/lib/cms_scanner/vulnerability.rb +2 -0
- data/lib/cms_scanner/web_site.rb +34 -2
- metadata +4 -6
- data/app/controllers.rb +0 -2
- data/app/finders.rb +0 -1
- data/app/formatters.rb +0 -4
- data/app/models.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19ca3bad75160815e98141684a64b01032d20ab64b6ad9820bad8ee8312efa6a
|
4
|
+
data.tar.gz: 0b26c2137534fea2e6ea40c79944a6db999819c93709239ae3a9786b8358d51e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89b98c3e832204d8cf90c6ae034a73c7478bfdd0a25722275f3d131bc578101257a8c471d070a5f3791ac50741579271940bd234ee5e2d0eb24e7eaa497d01be
|
7
|
+
data.tar.gz: 4bde15301bb4262dfb0fc6029ad42c0f6ef4617895b84a8e3ef197f6cde7f79196f85264ca840f535b2eedf58c3fb0a55ac75e6e5695ff0893b84c557a4e56b5
|
data/app/app.rb
CHANGED
@@ -1,4 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require_relative '
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Formatters
|
4
|
+
require_relative 'formatters/cli'
|
5
|
+
require_relative 'formatters/cli_no_colour'
|
6
|
+
require_relative 'formatters/cli_no_color'
|
7
|
+
require_relative 'formatters/json'
|
8
|
+
|
9
|
+
# Controllers
|
10
|
+
require_relative 'controllers/core'
|
11
|
+
require_relative 'controllers/interesting_findings'
|
12
|
+
|
13
|
+
# Models
|
14
|
+
require_relative 'models/interesting_finding'
|
15
|
+
require_relative 'models/robots_txt'
|
16
|
+
require_relative 'models/fantastico_fileslist'
|
17
|
+
require_relative 'models/headers'
|
18
|
+
require_relative 'models/xml_rpc'
|
19
|
+
require_relative 'models/version'
|
20
|
+
require_relative 'models/user'
|
21
|
+
|
22
|
+
# Finders
|
23
|
+
require_relative 'finders/interesting_findings'
|
data/app/controllers/core.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'core/cli_options'
|
2
4
|
|
3
5
|
module CMSScanner
|
@@ -37,22 +39,22 @@ module CMSScanner
|
|
37
39
|
|
38
40
|
case res.code
|
39
41
|
when 0
|
40
|
-
raise
|
42
|
+
raise Error::TargetDown, res
|
41
43
|
when 401
|
42
|
-
raise
|
44
|
+
raise Error::HTTPAuthRequired
|
43
45
|
when 403
|
44
|
-
raise
|
46
|
+
raise Error::AccessForbidden, parsed_options[:random_user_agent]
|
45
47
|
when 407
|
46
|
-
raise
|
48
|
+
raise Error::ProxyAuthRequired
|
47
49
|
end
|
48
50
|
|
49
51
|
# Checks for redirects
|
50
|
-
# An out of scope redirect will raise an
|
52
|
+
# An out of scope redirect will raise an Error::HTTPRedirect
|
51
53
|
effective_url = target.homepage_res.effective_url
|
52
54
|
|
53
55
|
return if target.in_scope?(effective_url)
|
54
56
|
|
55
|
-
raise
|
57
|
+
raise Error::HTTPRedirect, effective_url unless parsed_options[:ignore_main_redirect]
|
56
58
|
|
57
59
|
target.homepage_res = res
|
58
60
|
end
|
@@ -1,21 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
4
|
module Finders
|
3
5
|
module InterestingFindings
|
4
6
|
# FantasticoFileslist finder
|
5
7
|
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
8
|
# @return [ InterestingFinding ]
|
12
9
|
def aggressive(_opts = {})
|
13
|
-
|
10
|
+
path = 'fantastico_fileslist.txt'
|
11
|
+
res = target.head_and_get(path)
|
14
12
|
|
15
|
-
return
|
13
|
+
return if res.body.strip.empty?
|
16
14
|
return unless res.headers && res.headers['Content-Type'] =~ %r{\Atext/plain}
|
17
15
|
|
18
|
-
NS::FantasticoFileslist.new(url, confidence: 70, found_by: found_by)
|
16
|
+
NS::Model::FantasticoFileslist.new(target.url(path), confidence: 70, found_by: found_by)
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
4
|
module Finders
|
3
5
|
module InterestingFindings
|
@@ -5,7 +7,7 @@ module CMSScanner
|
|
5
7
|
class Headers < Finder
|
6
8
|
# @return [ InterestingFinding ]
|
7
9
|
def passive(_opts = {})
|
8
|
-
r = NS::Headers.new(target.homepage_url, confidence: 100, found_by: found_by)
|
10
|
+
r = NS::Model::Headers.new(target.homepage_url, confidence: 100, found_by: found_by)
|
9
11
|
|
10
12
|
r.interesting_entries.empty? ? nil : r
|
11
13
|
end
|
@@ -1,20 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
4
|
module Finders
|
3
5
|
module InterestingFindings
|
4
6
|
# Robots.txt finder
|
5
7
|
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
8
|
# @return [ InterestingFinding ]
|
12
9
|
def aggressive(_opts = {})
|
13
|
-
|
10
|
+
path = 'robots.txt'
|
11
|
+
res = target.head_and_get(path)
|
14
12
|
|
15
13
|
return unless res&.code == 200 && res.body =~ /(?:user-agent|(?:dis)?allow):/i
|
16
14
|
|
17
|
-
NS::RobotsTxt.new(url, confidence: 100, found_by: found_by)
|
15
|
+
NS::Model::RobotsTxt.new(target.url(path), confidence: 100, found_by: found_by)
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -1,22 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
4
|
module Finders
|
3
5
|
module InterestingFindings
|
4
6
|
# SearchReplaceDB2 finder
|
5
7
|
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
8
|
# @return [ InterestingFinding ]
|
12
9
|
def aggressive(_opts = {})
|
13
|
-
|
10
|
+
path = 'searchreplacedb2.php'
|
14
11
|
|
15
|
-
return unless
|
12
|
+
return unless target.head_and_get(path).body =~ /by interconnect/i
|
16
13
|
|
17
|
-
NS::InterestingFinding.new(url,
|
18
|
-
|
19
|
-
|
14
|
+
NS::Model::InterestingFinding.new(target.url(path),
|
15
|
+
confidence: 100,
|
16
|
+
found_by: found_by,
|
17
|
+
references: references)
|
20
18
|
end
|
21
19
|
|
22
20
|
def references
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
4
|
module Finders
|
3
5
|
module InterestingFindings
|
@@ -21,7 +23,7 @@ module CMSScanner
|
|
21
23
|
|
22
24
|
potential_urls << url
|
23
25
|
|
24
|
-
NS::XMLRPC.new(url, confidence: 30, found_by: 'Headers (Passive Detection)')
|
26
|
+
NS::Model::XMLRPC.new(url, confidence: 30, found_by: 'Headers (Passive Detection)')
|
25
27
|
end
|
26
28
|
|
27
29
|
# @return [ XMLRPC ]
|
@@ -33,8 +35,8 @@ module CMSScanner
|
|
33
35
|
|
34
36
|
potential_urls << url
|
35
37
|
|
36
|
-
return NS::XMLRPC.new(url, confidence: 30,
|
37
|
-
|
38
|
+
return NS::Model::XMLRPC.new(url, confidence: 30,
|
39
|
+
found_by: 'Link Tag (Passive Detection)')
|
38
40
|
end
|
39
41
|
nil
|
40
42
|
end
|
@@ -50,9 +52,9 @@ module CMSScanner
|
|
50
52
|
|
51
53
|
next unless res&.body =~ /<methodResponse>/i
|
52
54
|
|
53
|
-
return NS::XMLRPC.new(potential_url,
|
54
|
-
|
55
|
-
|
55
|
+
return NS::Model::XMLRPC.new(potential_url,
|
56
|
+
confidence: 100,
|
57
|
+
found_by: DIRECT_ACCESS)
|
56
58
|
end
|
57
59
|
nil
|
58
60
|
end
|
data/app/formatters/cli.rb
CHANGED
data/app/formatters/json.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
module Model
|
5
|
+
# FantasticoFileslist
|
6
|
+
class FantasticoFileslist < InterestingFinding
|
7
|
+
# @return [ Array<String> ] The interesting files/dirs detected
|
8
|
+
def interesting_entries
|
9
|
+
results = []
|
7
10
|
|
8
|
-
|
9
|
-
|
11
|
+
entries.each do |entry|
|
12
|
+
next unless entry =~ /(?:admin|\.log|\.sql|\.db)/i
|
10
13
|
|
11
|
-
|
14
|
+
results << entry
|
15
|
+
end
|
16
|
+
results
|
12
17
|
end
|
13
|
-
results
|
14
|
-
end
|
15
18
|
|
16
|
-
|
17
|
-
|
19
|
+
def references
|
20
|
+
{ url: ['http://www.acunetix.com/vulnerabilities/fantastico-fileslist/'] }
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
data/app/models/headers.rb
CHANGED
@@ -1,35 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CMSScanner
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
module Model
|
5
|
+
# Interesting Headers
|
6
|
+
class Headers < InterestingFinding
|
7
|
+
# @return [ Hash ] The headers
|
8
|
+
def entries
|
9
|
+
res = NS::Browser.get(url)
|
10
|
+
return [] unless res&.headers
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
res.headers
|
13
|
+
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
+
# @return [ Array<String> ] The interesting headers detected
|
16
|
+
def interesting_entries
|
17
|
+
results = []
|
15
18
|
|
16
|
-
|
17
|
-
|
19
|
+
entries.each do |header, value|
|
20
|
+
next if known_headers.include?(header.downcase)
|
18
21
|
|
19
|
-
|
22
|
+
results << "#{header}: #{[*value].join(', ')}"
|
23
|
+
end
|
24
|
+
results
|
20
25
|
end
|
21
|
-
results
|
22
|
-
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
# @return [ Array<String> ] Downcased known headers
|
28
|
+
def known_headers
|
29
|
+
%w[
|
30
|
+
age accept-ranges cache-control content-encoding content-length content-type connection date
|
31
|
+
etag expires keep-alive location last-modified link pragma set-cookie strict-transport-security
|
32
|
+
transfer-encoding vary x-cache x-content-security-policy x-content-type-options
|
33
|
+
x-frame-options x-language x-permitted-cross-domain-policies x-pingback x-varnish
|
34
|
+
x-webkit-csp x-xss-protection
|
35
|
+
]
|
36
|
+
end
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -1,44 +1,48 @@
|
|
1
|
-
|
2
|
-
# Interesting Finding
|
3
|
-
class InterestingFinding
|
4
|
-
include Finders::Finding
|
5
|
-
|
6
|
-
attr_reader :url
|
7
|
-
attr_writer :to_s
|
8
|
-
|
9
|
-
# @param [ String ] url
|
10
|
-
# @param [ Hash ] opts
|
11
|
-
# :to_s (override the to_s method)
|
12
|
-
# See Finders::Finding for other available options
|
13
|
-
def initialize(url, opts = {})
|
14
|
-
@url = url
|
15
|
-
@to_s = opts[:to_s]
|
16
|
-
|
17
|
-
parse_finding_options(opts)
|
18
|
-
end
|
19
|
-
|
20
|
-
# @return [ Array<String> ]
|
21
|
-
def entries
|
22
|
-
res = NS::Browser.get(url)
|
23
|
-
|
24
|
-
return [] unless res && res.headers['Content-Type'] =~ %r{\Atext/plain;}i
|
25
|
-
|
26
|
-
res.body.split("\n").reject { |s| s.strip.empty? }
|
27
|
-
end
|
1
|
+
# frozen_string_literal: true
|
28
2
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
3
|
+
module CMSScanner
|
4
|
+
module Model
|
5
|
+
# Interesting Finding
|
6
|
+
class InterestingFinding
|
7
|
+
include Finders::Finding
|
8
|
+
|
9
|
+
attr_reader :url
|
10
|
+
attr_writer :to_s
|
11
|
+
|
12
|
+
# @param [ String ] url
|
13
|
+
# @param [ Hash ] opts
|
14
|
+
# :to_s (override the to_s method)
|
15
|
+
# See Finders::Finding for other available options
|
16
|
+
def initialize(url, opts = {})
|
17
|
+
@url = url
|
18
|
+
@to_s = opts[:to_s]
|
19
|
+
|
20
|
+
parse_finding_options(opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [ Array<String> ]
|
24
|
+
def entries
|
25
|
+
res = NS::Browser.get(url)
|
26
|
+
|
27
|
+
return [] unless res && res.headers['Content-Type'] =~ %r{\Atext/plain;}i
|
28
|
+
|
29
|
+
res.body.split("\n").reject { |s| s.strip.empty? }
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [ String ]
|
33
|
+
def to_s
|
34
|
+
@to_s || url
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [ String ]
|
38
|
+
def type
|
39
|
+
@type ||= self.class.to_s.demodulize.underscore
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [ Boolean ]
|
43
|
+
def ==(other)
|
44
|
+
self.class == other.class && to_s == other.to_s
|
45
|
+
end
|
42
46
|
end
|
43
47
|
end
|
44
48
|
end
|