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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +26 -0
  4. data/app/app.rb +24 -0
  5. data/app/controllers/core/cli_options.rb +117 -0
  6. data/app/controllers/core.rb +82 -0
  7. data/app/controllers/interesting_findings.rb +25 -0
  8. data/app/finders/interesting_findings/fantastico_fileslist.rb +21 -0
  9. data/app/finders/interesting_findings/headers.rb +17 -0
  10. data/app/finders/interesting_findings/robots_txt.rb +20 -0
  11. data/app/finders/interesting_findings/search_replace_db_2.rb +19 -0
  12. data/app/finders/interesting_findings/xml_rpc.rb +61 -0
  13. data/app/finders/interesting_findings.rb +25 -0
  14. data/app/formatters/cli.rb +65 -0
  15. data/app/formatters/cli_no_color.rb +9 -0
  16. data/app/formatters/cli_no_colour.rb +17 -0
  17. data/app/formatters/json.rb +14 -0
  18. data/app/models/fantastico_fileslist.rb +34 -0
  19. data/app/models/headers.rb +44 -0
  20. data/app/models/interesting_finding.rb +48 -0
  21. data/app/models/robots_txt.rb +31 -0
  22. data/app/models/search_replace_db_2.rb +17 -0
  23. data/app/models/user.rb +35 -0
  24. data/app/models/version.rb +49 -0
  25. data/app/models/xml_rpc.rb +78 -0
  26. data/app/user_agents.txt +46 -0
  27. data/app/views/cli/core/banner.erb +1 -0
  28. data/app/views/cli/core/finished.erb +8 -0
  29. data/app/views/cli/core/help.erb +4 -0
  30. data/app/views/cli/core/started.erb +6 -0
  31. data/app/views/cli/core/version.erb +1 -0
  32. data/app/views/cli/interesting_findings/_array.erb +10 -0
  33. data/app/views/cli/interesting_findings/findings.erb +23 -0
  34. data/app/views/cli/scan_aborted.erb +5 -0
  35. data/app/views/cli/usage.erb +3 -0
  36. data/app/views/json/core/banner.erb +1 -0
  37. data/app/views/json/core/finished.erb +10 -0
  38. data/app/views/json/core/help.erb +4 -0
  39. data/app/views/json/core/started.erb +5 -0
  40. data/app/views/json/core/version.erb +1 -0
  41. data/app/views/json/interesting_findings/findings.erb +24 -0
  42. data/app/views/json/scan_aborted.erb +5 -0
  43. data/lib/cms_scanner/browser/actions.rb +48 -0
  44. data/lib/cms_scanner/browser/options.rb +90 -0
  45. data/lib/cms_scanner/browser.rb +96 -0
  46. data/lib/cms_scanner/cache/file_store.rb +77 -0
  47. data/lib/cms_scanner/cache/typhoeus.rb +25 -0
  48. data/lib/cms_scanner/controller.rb +105 -0
  49. data/lib/cms_scanner/controllers.rb +67 -0
  50. data/lib/cms_scanner/errors/http.rb +72 -0
  51. data/lib/cms_scanner/errors/scan.rb +14 -0
  52. data/lib/cms_scanner/errors.rb +11 -0
  53. data/lib/cms_scanner/exit_code.rb +25 -0
  54. data/lib/cms_scanner/finders/base_finders.rb +45 -0
  55. data/lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb +121 -0
  56. data/lib/cms_scanner/finders/finder/enumerator.rb +77 -0
  57. data/lib/cms_scanner/finders/finder/fingerprinter.rb +48 -0
  58. data/lib/cms_scanner/finders/finder/smart_url_checker/findings.rb +33 -0
  59. data/lib/cms_scanner/finders/finder/smart_url_checker.rb +60 -0
  60. data/lib/cms_scanner/finders/finder.rb +75 -0
  61. data/lib/cms_scanner/finders/finding.rb +54 -0
  62. data/lib/cms_scanner/finders/findings.rb +26 -0
  63. data/lib/cms_scanner/finders/independent_finder.rb +30 -0
  64. data/lib/cms_scanner/finders/independent_finders.rb +26 -0
  65. data/lib/cms_scanner/finders/same_type_finder.rb +19 -0
  66. data/lib/cms_scanner/finders/same_type_finders.rb +26 -0
  67. data/lib/cms_scanner/finders/unique_finder.rb +19 -0
  68. data/lib/cms_scanner/finders/unique_finders.rb +47 -0
  69. data/lib/cms_scanner/finders.rb +12 -0
  70. data/lib/cms_scanner/formatter/buffer.rb +17 -0
  71. data/lib/cms_scanner/formatter.rb +149 -0
  72. data/lib/cms_scanner/helper.rb +7 -0
  73. data/lib/cms_scanner/numeric.rb +13 -0
  74. data/lib/cms_scanner/parsed_cli.rb +37 -0
  75. data/lib/cms_scanner/progressbar_null_output.rb +23 -0
  76. data/lib/cms_scanner/public_suffix/domain.rb +42 -0
  77. data/lib/cms_scanner/references.rb +132 -0
  78. data/lib/cms_scanner/scan.rb +88 -0
  79. data/lib/cms_scanner/target/hashes.rb +45 -0
  80. data/lib/cms_scanner/target/platform/php.rb +62 -0
  81. data/lib/cms_scanner/target/platform.rb +3 -0
  82. data/lib/cms_scanner/target/scope.rb +103 -0
  83. data/lib/cms_scanner/target/server/apache.rb +27 -0
  84. data/lib/cms_scanner/target/server/generic.rb +72 -0
  85. data/lib/cms_scanner/target/server/iis.rb +29 -0
  86. data/lib/cms_scanner/target/server/nginx.rb +27 -0
  87. data/lib/cms_scanner/target/server.rb +6 -0
  88. data/lib/cms_scanner/target.rb +124 -0
  89. data/lib/cms_scanner/typhoeus/hydra.rb +12 -0
  90. data/lib/cms_scanner/typhoeus/response.rb +27 -0
  91. data/lib/cms_scanner/version.rb +6 -0
  92. data/lib/cms_scanner/vulnerability.rb +46 -0
  93. data/lib/cms_scanner/web_site.rb +145 -0
  94. data/lib/cms_scanner.rb +141 -0
  95. 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
@@ -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
@@ -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,4 @@
1
+ <%= @help %>
2
+ <% if @simple -%>
3
+ [!] To see full list of options use --hh.
4
+ <% end -%>
@@ -0,0 +1,6 @@
1
+ <%= info_icon %> URL: <%= @url %> [<%= @ip %>]
2
+ <% if @url != @effective_url -%>
3
+ <%= info_icon %> Effective URL: <%= @effective_url %>
4
+ <% end -%>
5
+ <%= info_icon %> Started: <%= @start_time.asctime %>
6
+
@@ -0,0 +1 @@
1
+ Version: <%= NS::VERSION %>
@@ -0,0 +1,10 @@
1
+ <% unless @a.empty? -%>
2
+ <% if @a.size == 1 -%>
3
+ | <%= @s %>: <%= @a.first %>
4
+ <% else -%>
5
+ | <%= @p %>:
6
+ <% @a.each do |line| -%>
7
+ | - <%= line %>
8
+ <% end -%>
9
+ <% end -%>
10
+ <% end -%>
@@ -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,5 @@
1
+
2
+ Scan Aborted: <%= @reason %>
3
+ <% if @verbose -%>
4
+ Trace: <%= @trace.join("\n") %>
5
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <%= @msg %>
2
+
3
+ Please use --help/-h for the list of available options.
@@ -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,4 @@
1
+ "help": <%= @help.to_s.to_json %>,
2
+ <% if @simple -%>
3
+ "full_help": "To see full list of options use --hh.",
4
+ <% end -%>
@@ -0,0 +1,5 @@
1
+ "start_time": <%= @start_time.to_i %>,
2
+ "start_memory": <%= @start_memory.to_i %>,
3
+ "target_url": <%= @url.to_s.to_json %>,
4
+ "target_ip": <%= @ip.to_s.to_json %>,
5
+ "effective_url": <%= @effective_url.to_s.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,5 @@
1
+ "scan_aborted": <%= @reason.to_json %>,
2
+ "target_url": <%= @url.to_json %>,
3
+ <% if @verbose -%>
4
+ "trace": <%= @trace.to_json %>,
5
+ <% end %>
@@ -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