new_cms_scanner 0.13.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +26 -0
- data/app/app.rb +24 -0
- data/app/controllers/core/cli_options.rb +117 -0
- data/app/controllers/core.rb +82 -0
- data/app/controllers/interesting_findings.rb +25 -0
- data/app/finders/interesting_findings/fantastico_fileslist.rb +21 -0
- data/app/finders/interesting_findings/headers.rb +17 -0
- data/app/finders/interesting_findings/robots_txt.rb +20 -0
- data/app/finders/interesting_findings/search_replace_db_2.rb +19 -0
- data/app/finders/interesting_findings/xml_rpc.rb +61 -0
- data/app/finders/interesting_findings.rb +25 -0
- data/app/formatters/cli.rb +65 -0
- data/app/formatters/cli_no_color.rb +9 -0
- data/app/formatters/cli_no_colour.rb +17 -0
- data/app/formatters/json.rb +14 -0
- data/app/models/fantastico_fileslist.rb +34 -0
- data/app/models/headers.rb +44 -0
- data/app/models/interesting_finding.rb +48 -0
- data/app/models/robots_txt.rb +31 -0
- data/app/models/search_replace_db_2.rb +17 -0
- data/app/models/user.rb +35 -0
- data/app/models/version.rb +49 -0
- data/app/models/xml_rpc.rb +78 -0
- data/app/user_agents.txt +46 -0
- data/app/views/cli/core/banner.erb +1 -0
- data/app/views/cli/core/finished.erb +8 -0
- data/app/views/cli/core/help.erb +4 -0
- data/app/views/cli/core/started.erb +6 -0
- data/app/views/cli/core/version.erb +1 -0
- data/app/views/cli/interesting_findings/_array.erb +10 -0
- data/app/views/cli/interesting_findings/findings.erb +23 -0
- data/app/views/cli/scan_aborted.erb +5 -0
- data/app/views/cli/usage.erb +3 -0
- data/app/views/json/core/banner.erb +1 -0
- data/app/views/json/core/finished.erb +10 -0
- data/app/views/json/core/help.erb +4 -0
- data/app/views/json/core/started.erb +5 -0
- data/app/views/json/core/version.erb +1 -0
- data/app/views/json/interesting_findings/findings.erb +24 -0
- data/app/views/json/scan_aborted.erb +5 -0
- data/lib/cms_scanner/browser/actions.rb +48 -0
- data/lib/cms_scanner/browser/options.rb +90 -0
- data/lib/cms_scanner/browser.rb +96 -0
- data/lib/cms_scanner/cache/file_store.rb +77 -0
- data/lib/cms_scanner/cache/typhoeus.rb +25 -0
- data/lib/cms_scanner/controller.rb +105 -0
- data/lib/cms_scanner/controllers.rb +67 -0
- data/lib/cms_scanner/errors/http.rb +72 -0
- data/lib/cms_scanner/errors/scan.rb +14 -0
- data/lib/cms_scanner/errors.rb +11 -0
- data/lib/cms_scanner/exit_code.rb +25 -0
- data/lib/cms_scanner/finders/base_finders.rb +45 -0
- data/lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb +121 -0
- data/lib/cms_scanner/finders/finder/enumerator.rb +77 -0
- data/lib/cms_scanner/finders/finder/fingerprinter.rb +48 -0
- data/lib/cms_scanner/finders/finder/smart_url_checker/findings.rb +33 -0
- data/lib/cms_scanner/finders/finder/smart_url_checker.rb +60 -0
- data/lib/cms_scanner/finders/finder.rb +75 -0
- data/lib/cms_scanner/finders/finding.rb +54 -0
- data/lib/cms_scanner/finders/findings.rb +26 -0
- data/lib/cms_scanner/finders/independent_finder.rb +30 -0
- data/lib/cms_scanner/finders/independent_finders.rb +26 -0
- data/lib/cms_scanner/finders/same_type_finder.rb +19 -0
- data/lib/cms_scanner/finders/same_type_finders.rb +26 -0
- data/lib/cms_scanner/finders/unique_finder.rb +19 -0
- data/lib/cms_scanner/finders/unique_finders.rb +47 -0
- data/lib/cms_scanner/finders.rb +12 -0
- data/lib/cms_scanner/formatter/buffer.rb +17 -0
- data/lib/cms_scanner/formatter.rb +149 -0
- data/lib/cms_scanner/helper.rb +7 -0
- data/lib/cms_scanner/numeric.rb +13 -0
- data/lib/cms_scanner/parsed_cli.rb +37 -0
- data/lib/cms_scanner/progressbar_null_output.rb +23 -0
- data/lib/cms_scanner/public_suffix/domain.rb +42 -0
- data/lib/cms_scanner/references.rb +132 -0
- data/lib/cms_scanner/scan.rb +88 -0
- data/lib/cms_scanner/target/hashes.rb +45 -0
- data/lib/cms_scanner/target/platform/php.rb +62 -0
- data/lib/cms_scanner/target/platform.rb +3 -0
- data/lib/cms_scanner/target/scope.rb +103 -0
- data/lib/cms_scanner/target/server/apache.rb +27 -0
- data/lib/cms_scanner/target/server/generic.rb +72 -0
- data/lib/cms_scanner/target/server/iis.rb +29 -0
- data/lib/cms_scanner/target/server/nginx.rb +27 -0
- data/lib/cms_scanner/target/server.rb +6 -0
- data/lib/cms_scanner/target.rb +124 -0
- data/lib/cms_scanner/typhoeus/hydra.rb +12 -0
- data/lib/cms_scanner/typhoeus/response.rb +27 -0
- data/lib/cms_scanner/version.rb +6 -0
- data/lib/cms_scanner/vulnerability.rb +46 -0
- data/lib/cms_scanner/web_site.rb +145 -0
- data/lib/cms_scanner.rb +141 -0
- metadata +426 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
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
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
module Model
|
5
|
+
# Robots.txt
|
6
|
+
class RobotsTxt < InterestingFinding
|
7
|
+
# @return [ String ]
|
8
|
+
def to_s
|
9
|
+
@to_s ||= "robots.txt found: #{url}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# @todo Better detection, currently everything not empty or / is returned
|
13
|
+
#
|
14
|
+
# @return [ Array<String> ] The interesting Allow/Disallow rules detected
|
15
|
+
def interesting_entries
|
16
|
+
results = []
|
17
|
+
|
18
|
+
entries.each do |entry|
|
19
|
+
next unless entry =~ /\A(?:dis)?allow:\s*(.+)\z/i
|
20
|
+
|
21
|
+
match = Regexp.last_match(1)
|
22
|
+
next if match == '/'
|
23
|
+
|
24
|
+
results << match
|
25
|
+
end
|
26
|
+
|
27
|
+
results.uniq
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
module Model
|
5
|
+
# SearchReplaceDB2
|
6
|
+
class SearchReplaceDB2 < InterestingFinding
|
7
|
+
# @return [ String ]
|
8
|
+
def to_s
|
9
|
+
@to_s ||= "Search Replace DB script found: #{url}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def references
|
13
|
+
@references ||= { url: ['https://interconnectit.com/products/search-and-replace-for-wordpress-databases/'] }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/app/models/user.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
module Model
|
5
|
+
# User
|
6
|
+
class User
|
7
|
+
include Finders::Finding
|
8
|
+
|
9
|
+
attr_accessor :password
|
10
|
+
attr_reader :id, :username
|
11
|
+
|
12
|
+
# @param [ String ] username
|
13
|
+
# @param [ Hash ] opts
|
14
|
+
# @option opts [ Integer ] :id
|
15
|
+
# @option opts [ String ] :password
|
16
|
+
def initialize(username, opts = {})
|
17
|
+
@username = username
|
18
|
+
@password = opts[:password]
|
19
|
+
@id = opts[:id]
|
20
|
+
|
21
|
+
parse_finding_options(opts)
|
22
|
+
end
|
23
|
+
|
24
|
+
def ==(other)
|
25
|
+
return false unless self.class == other.class
|
26
|
+
|
27
|
+
username == other.username && password == other.password
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
username
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
module Model
|
5
|
+
# Version
|
6
|
+
class Version
|
7
|
+
include Finders::Finding
|
8
|
+
|
9
|
+
attr_reader :number
|
10
|
+
|
11
|
+
def initialize(number, opts = {})
|
12
|
+
@number = number.to_s
|
13
|
+
@number = "0#{number}" if @number[0, 1] == '.'
|
14
|
+
|
15
|
+
parse_finding_options(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [ Version, String ] other
|
19
|
+
# rubocop:disable Style/NumericPredicate
|
20
|
+
def ==(other)
|
21
|
+
(self <=> other) == 0
|
22
|
+
end
|
23
|
+
# rubocop:enable all
|
24
|
+
|
25
|
+
# @param [ Version, String ] other
|
26
|
+
def <(other)
|
27
|
+
(self <=> other) == -1
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [ Version, String ] other
|
31
|
+
def >(other)
|
32
|
+
(self <=> other) == 1
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [ Version, String ] other
|
36
|
+
def <=>(other)
|
37
|
+
other = self.class.new(other) unless other.is_a?(self.class) # handle potential '.1' version
|
38
|
+
|
39
|
+
Gem::Version.new(number) <=> Gem::Version.new(other.number)
|
40
|
+
rescue ArgumentError
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
number
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
module Model
|
5
|
+
# XML RPC
|
6
|
+
class XMLRPC < InterestingFinding
|
7
|
+
# @return [ String ]
|
8
|
+
def to_s
|
9
|
+
@to_s ||= "XML-RPC seems to be enabled: #{url}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [ Browser ]
|
13
|
+
def browser
|
14
|
+
@browser ||= NS::Browser.instance
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [ Array<String> ]
|
18
|
+
def available_methods
|
19
|
+
return @available_methods if @available_methods
|
20
|
+
|
21
|
+
@available_methods = []
|
22
|
+
|
23
|
+
res = method_call('system.listMethods').run
|
24
|
+
doc = Nokogiri::XML.parse(res.body)
|
25
|
+
|
26
|
+
doc.search('methodResponse params param value array data value string').each do |s|
|
27
|
+
@available_methods << s.text
|
28
|
+
end
|
29
|
+
|
30
|
+
@available_methods
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [ Boolean ] Whether or not the XMLRPC is enabled
|
34
|
+
def enabled?
|
35
|
+
!available_methods.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [ String ] method_name
|
39
|
+
# @param [ Array ] method_params
|
40
|
+
# @param [ Hash ] request_params
|
41
|
+
#
|
42
|
+
# @return [ Typhoeus::Request ]
|
43
|
+
def method_call(method_name, method_params = [], request_params = {})
|
44
|
+
browser.forge_request(
|
45
|
+
url,
|
46
|
+
request_params.merge(
|
47
|
+
method: :post,
|
48
|
+
body: ::XMLRPC::Create.new.methodCall(method_name, *method_params)
|
49
|
+
)
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [ Array<Array> ] methods_and_params
|
54
|
+
# @param [ Hash ] request_params
|
55
|
+
#
|
56
|
+
# Example of methods_and_params:
|
57
|
+
# [
|
58
|
+
# [method1, param1, param2],
|
59
|
+
# [method2, param1],
|
60
|
+
# [method3]
|
61
|
+
# ]
|
62
|
+
#
|
63
|
+
# @return [ Typhoeus::Request ]
|
64
|
+
def multi_call(methods_and_params = [], request_params = {})
|
65
|
+
browser.forge_request(
|
66
|
+
url,
|
67
|
+
request_params.merge(
|
68
|
+
method: :post,
|
69
|
+
body: ::XMLRPC::Create.new.methodCall(
|
70
|
+
'system.multicall',
|
71
|
+
methods_and_params.collect { |m| { methodName: m[0], params: m[1..-1] } }
|
72
|
+
)
|
73
|
+
)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/app/user_agents.txt
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Windows
|
2
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5
|
3
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14
|
4
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27
|
5
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1
|
6
|
+
Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)
|
7
|
+
Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
|
8
|
+
Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
|
9
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
|
10
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6
|
11
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1
|
12
|
+
Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0
|
13
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1
|
14
|
+
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)
|
15
|
+
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
|
16
|
+
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0)
|
17
|
+
Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00
|
18
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5
|
19
|
+
|
20
|
+
# MAC
|
21
|
+
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13
|
22
|
+
Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15
|
23
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
|
24
|
+
Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3
|
25
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3
|
26
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1
|
27
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10
|
28
|
+
|
29
|
+
# Linux
|
30
|
+
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1
|
31
|
+
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24
|
32
|
+
Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9
|
33
|
+
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0
|
34
|
+
Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0
|
35
|
+
Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00
|
36
|
+
Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.1.19) Gecko/20110430 shadowfox/7.0 (like Firefox/7.0
|
37
|
+
|
38
|
+
# iPad
|
39
|
+
Mozilla/5.0 (iPad; CPU OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D201 Safari/9537.53
|
40
|
+
Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53
|
41
|
+
Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B329 Safari/8536.25
|
42
|
+
|
43
|
+
# iPhone
|
44
|
+
Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53
|
45
|
+
Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_3 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B511 Safari/9537.53
|
46
|
+
Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D201 Safari/9537.53
|
@@ -0,0 +1 @@
|
|
1
|
+
<% # Empty file, the banner should be implemented in each scanner %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
<%= info_icon %> Finished: <%= @stop_time.asctime %>
|
3
|
+
<%= info_icon %> Requests Done: <%= @requests_done %>
|
4
|
+
<%= info_icon %> Cached Requests: <%= @cached_requests %>
|
5
|
+
<%= info_icon %> Data Sent: <%= @data_sent.bytes_to_human %>
|
6
|
+
<%= info_icon %> Data Received: <%= @data_received.bytes_to_human %>
|
7
|
+
<%= info_icon %> Memory used: <%= @used_memory.bytes_to_human %>
|
8
|
+
<%= info_icon %> Elapsed time: <%= Time.at(@elapsed).utc.strftime('%H:%M:%S') %>
|
@@ -0,0 +1 @@
|
|
1
|
+
Version: <%= NS::VERSION %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<% unless @findings.empty? -%>
|
2
|
+
Interesting Finding(s):
|
3
|
+
<% @findings.each do |finding| -%>
|
4
|
+
|
5
|
+
<%= info_icon %> <%= finding %>
|
6
|
+
<%= render('_array', a: finding.interesting_entries, s: 'Interesting Entry', p: 'Interesting Entries') -%>
|
7
|
+
| Found By: <%= finding.found_by %>
|
8
|
+
<% if finding.confidence > 0 -%>
|
9
|
+
| Confidence: <%= finding.confidence %>%
|
10
|
+
<% end -%>
|
11
|
+
<% unless (confirmed = finding.confirmed_by).empty? -%>
|
12
|
+
<% if confirmed.size == 1 -%>
|
13
|
+
| Confirmed By: <%= confirmed.first.found_by %><% if confirmed.first.confidence > 0 %>, <%= confirmed.first.confidence %>% confidence<% end %>
|
14
|
+
<% else -%>
|
15
|
+
| Confirmed By:
|
16
|
+
<% confirmed.each do |c| -%>
|
17
|
+
| - <%= c.found_by %><% if c.confidence > 0 %>, <%= c.confidence %>% confidence<% end %>
|
18
|
+
<% end -%>
|
19
|
+
<% end -%>
|
20
|
+
<% end -%>
|
21
|
+
<%= render('_array', a: finding.references_urls, s: 'Reference', p: 'References') -%>
|
22
|
+
<% end -%>
|
23
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<% # Empty file, the banner should be implemented in each scanner %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"stop_time": <%= @stop_time.to_i %>,
|
2
|
+
"elapsed": <%= @elapsed.to_i %>,
|
3
|
+
"requests_done": <%= @requests_done.to_i %>,
|
4
|
+
"cached_requests": <%= @cached_requests.to_i %>,
|
5
|
+
"data_sent": <%= @data_sent.to_i %>,
|
6
|
+
"data_sent_humanised": <%= @data_sent.bytes_to_human.to_json %>,
|
7
|
+
"data_received": <%= @data_received.to_i %>,
|
8
|
+
"data_received_humanised": <%= @data_received.bytes_to_human.to_json %>,
|
9
|
+
"used_memory": <%= @used_memory.to_i %>,
|
10
|
+
"used_memory_humanised": <%= @used_memory.bytes_to_human.to_json %>,
|
@@ -0,0 +1 @@
|
|
1
|
+
"version": <%= NS::VERSION.to_s.to_json %>,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"interesting_findings": [
|
2
|
+
<% unless @findings.empty? -%>
|
3
|
+
<% last_index = @findings.size - 1 %>
|
4
|
+
<% @findings.each.with_index do |finding, index| -%>
|
5
|
+
{
|
6
|
+
"url": <%= finding.url.to_s.to_json %>,
|
7
|
+
"to_s": <%= finding.to_s.to_json %>,
|
8
|
+
"type": <%= finding.type.to_json %>,
|
9
|
+
"found_by": <%= finding.found_by.to_s.to_json %>,
|
10
|
+
"confidence": <%= finding.confidence.to_json %>,
|
11
|
+
"confirmed_by": {
|
12
|
+
<% unless (confirmed = finding.confirmed_by).empty? -%>
|
13
|
+
<% c_last_index = confirmed.size - 1 %>
|
14
|
+
<% confirmed.each.with_index do |c, i| -%>
|
15
|
+
<%= c.found_by.to_s.to_json %>: { "confidence": <%= c.confidence.to_json %> }<% unless i == c_last_index %>,<% end %>
|
16
|
+
<% end -%>
|
17
|
+
<% end -%>
|
18
|
+
},
|
19
|
+
"references": <%= finding.references.to_json %>,
|
20
|
+
"interesting_entries": <%= finding.interesting_entries.to_json %>
|
21
|
+
}<% unless index == last_index %>,<% end %>
|
22
|
+
<% end -%>
|
23
|
+
<% end -%>
|
24
|
+
],
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
class Browser
|
5
|
+
# Browser Actions (get, post etc)
|
6
|
+
module Actions
|
7
|
+
# @param [ String ] url
|
8
|
+
# @param [ Hash ] params
|
9
|
+
#
|
10
|
+
# @return [ Typhoeus::Request ]
|
11
|
+
def forge_request(url, params = {})
|
12
|
+
NS::Browser.instance.forge_request(url, params)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [ String ] url
|
16
|
+
# @param [ Hash ] params
|
17
|
+
#
|
18
|
+
# @return [ Typhoeus::Response ]
|
19
|
+
def get(url, params = {})
|
20
|
+
forge_request(url, params.merge(method: :get)).run
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param [ String ] url
|
24
|
+
# @param [ Hash ] params
|
25
|
+
#
|
26
|
+
# @return [ Typhoeus::Response ]
|
27
|
+
def post(url, params = {})
|
28
|
+
forge_request(url, params.merge(method: :post)).run
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param [ String ] url
|
32
|
+
# @param [ Hash ] params
|
33
|
+
#
|
34
|
+
# @return [ Typhoeus::Response ]
|
35
|
+
def head(url, params = {})
|
36
|
+
forge_request(url, params.merge(method: :head)).run
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param [ String ] url
|
40
|
+
# @param [ Hash ] params
|
41
|
+
#
|
42
|
+
# @return [ Typhoeus::Response ]
|
43
|
+
def get_and_follow_location(url, params = {})
|
44
|
+
get(url, { followlocation: true, maxredirs: 3 }.merge(params))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
# Options available in the Browser
|
5
|
+
class Browser
|
6
|
+
OPTIONS = %i[
|
7
|
+
cache_ttl
|
8
|
+
cookie_jar
|
9
|
+
cookie_string
|
10
|
+
connect_timeout
|
11
|
+
disable_tls_checks
|
12
|
+
headers
|
13
|
+
http_auth
|
14
|
+
max_threads
|
15
|
+
proxy
|
16
|
+
proxy_auth
|
17
|
+
random_user_agent
|
18
|
+
request_timeout
|
19
|
+
throttle
|
20
|
+
url
|
21
|
+
user_agent
|
22
|
+
user_agents_list
|
23
|
+
vhost
|
24
|
+
].freeze
|
25
|
+
|
26
|
+
attr_accessor(*OPTIONS)
|
27
|
+
|
28
|
+
# @return [ String ]
|
29
|
+
def default_user_agent
|
30
|
+
"#{NS} v#{NS::VERSION}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [ Typhoeus::Hydra ]
|
34
|
+
def hydra
|
35
|
+
@hydra ||= Typhoeus::Hydra.new(max_concurrency: max_threads || 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [ Hash ] options
|
39
|
+
def load_options(options = {})
|
40
|
+
OPTIONS.each do |sym|
|
41
|
+
send("#{sym}=", options[sym]) if options.key?(sym)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set the threads attribute and update hydra accordinly
|
46
|
+
# If the throttle attribute is > 0, max_threads will be forced to 1
|
47
|
+
#
|
48
|
+
# @param [ Integer ] number
|
49
|
+
def max_threads=(number)
|
50
|
+
@max_threads = number.to_i.positive? && throttle.zero? ? number.to_i : 1
|
51
|
+
|
52
|
+
hydra.max_concurrency = @max_threads
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [ String ] The user agent
|
56
|
+
def user_agent
|
57
|
+
@user_agent ||= random_user_agent ? user_agents.sample : default_user_agent
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [ Array<String> ]
|
61
|
+
def user_agents
|
62
|
+
return @user_agents if @user_agents
|
63
|
+
|
64
|
+
@user_agents = []
|
65
|
+
|
66
|
+
# The user_agents_list is managed by the CLI options, with the default being
|
67
|
+
# APP_DIR/user_agents.txt
|
68
|
+
File.open(user_agents_list).each do |line|
|
69
|
+
next if line == "\n" || line[0, 1] == '#'
|
70
|
+
|
71
|
+
@user_agents << line.chomp
|
72
|
+
end
|
73
|
+
|
74
|
+
@user_agents
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param [ value ] The throttle time in milliseconds
|
78
|
+
#
|
79
|
+
# if value > 0, the max_threads will be set to 1
|
80
|
+
def throttle=(value)
|
81
|
+
@throttle = value.to_i.abs / 1000.0
|
82
|
+
|
83
|
+
self.max_threads = 1 if @throttle.positive?
|
84
|
+
end
|
85
|
+
|
86
|
+
def trottle!
|
87
|
+
sleep(throttle) if throttle.positive?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|