new_cms_scanner 0.13.7
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 +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
|