cms_scanner 0.0.41.10 → 0.0.42.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|