railroader 4.3.4

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 (165) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +1091 -0
  3. data/FEATURES +16 -0
  4. data/README.md +174 -0
  5. data/bin/railroader +8 -0
  6. data/lib/railroader/app_tree.rb +191 -0
  7. data/lib/railroader/call_index.rb +219 -0
  8. data/lib/railroader/checks/base_check.rb +505 -0
  9. data/lib/railroader/checks/check_basic_auth.rb +88 -0
  10. data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
  11. data/lib/railroader/checks/check_content_tag.rb +200 -0
  12. data/lib/railroader/checks/check_create_with.rb +74 -0
  13. data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
  14. data/lib/railroader/checks/check_default_routes.rb +86 -0
  15. data/lib/railroader/checks/check_deserialize.rb +56 -0
  16. data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
  17. data/lib/railroader/checks/check_digest_dos.rb +38 -0
  18. data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
  19. data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
  20. data/lib/railroader/checks/check_escape_function.rb +21 -0
  21. data/lib/railroader/checks/check_evaluation.rb +35 -0
  22. data/lib/railroader/checks/check_execute.rb +189 -0
  23. data/lib/railroader/checks/check_file_access.rb +71 -0
  24. data/lib/railroader/checks/check_file_disclosure.rb +35 -0
  25. data/lib/railroader/checks/check_filter_skipping.rb +31 -0
  26. data/lib/railroader/checks/check_forgery_setting.rb +81 -0
  27. data/lib/railroader/checks/check_header_dos.rb +31 -0
  28. data/lib/railroader/checks/check_i18n_xss.rb +48 -0
  29. data/lib/railroader/checks/check_jruby_xml.rb +36 -0
  30. data/lib/railroader/checks/check_json_encoding.rb +47 -0
  31. data/lib/railroader/checks/check_json_parsing.rb +107 -0
  32. data/lib/railroader/checks/check_link_to.rb +132 -0
  33. data/lib/railroader/checks/check_link_to_href.rb +146 -0
  34. data/lib/railroader/checks/check_mail_to.rb +49 -0
  35. data/lib/railroader/checks/check_mass_assignment.rb +196 -0
  36. data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
  37. data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
  38. data/lib/railroader/checks/check_model_attributes.rb +119 -0
  39. data/lib/railroader/checks/check_model_serialize.rb +67 -0
  40. data/lib/railroader/checks/check_nested_attributes.rb +38 -0
  41. data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
  42. data/lib/railroader/checks/check_number_to_currency.rb +74 -0
  43. data/lib/railroader/checks/check_permit_attributes.rb +43 -0
  44. data/lib/railroader/checks/check_quote_table_name.rb +40 -0
  45. data/lib/railroader/checks/check_redirect.rb +256 -0
  46. data/lib/railroader/checks/check_regex_dos.rb +68 -0
  47. data/lib/railroader/checks/check_render.rb +97 -0
  48. data/lib/railroader/checks/check_render_dos.rb +37 -0
  49. data/lib/railroader/checks/check_render_inline.rb +53 -0
  50. data/lib/railroader/checks/check_response_splitting.rb +21 -0
  51. data/lib/railroader/checks/check_route_dos.rb +42 -0
  52. data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
  53. data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
  54. data/lib/railroader/checks/check_secrets.rb +40 -0
  55. data/lib/railroader/checks/check_select_tag.rb +59 -0
  56. data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
  57. data/lib/railroader/checks/check_send.rb +47 -0
  58. data/lib/railroader/checks/check_send_file.rb +19 -0
  59. data/lib/railroader/checks/check_session_manipulation.rb +35 -0
  60. data/lib/railroader/checks/check_session_settings.rb +176 -0
  61. data/lib/railroader/checks/check_simple_format.rb +58 -0
  62. data/lib/railroader/checks/check_single_quotes.rb +101 -0
  63. data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
  64. data/lib/railroader/checks/check_sql.rb +700 -0
  65. data/lib/railroader/checks/check_sql_cves.rb +106 -0
  66. data/lib/railroader/checks/check_ssl_verify.rb +48 -0
  67. data/lib/railroader/checks/check_strip_tags.rb +89 -0
  68. data/lib/railroader/checks/check_symbol_dos.rb +71 -0
  69. data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
  70. data/lib/railroader/checks/check_translate_bug.rb +45 -0
  71. data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
  72. data/lib/railroader/checks/check_unscoped_find.rb +57 -0
  73. data/lib/railroader/checks/check_validation_regex.rb +116 -0
  74. data/lib/railroader/checks/check_weak_hash.rb +148 -0
  75. data/lib/railroader/checks/check_without_protection.rb +80 -0
  76. data/lib/railroader/checks/check_xml_dos.rb +45 -0
  77. data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
  78. data/lib/railroader/checks.rb +209 -0
  79. data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
  80. data/lib/railroader/commandline.rb +179 -0
  81. data/lib/railroader/differ.rb +66 -0
  82. data/lib/railroader/file_parser.rb +54 -0
  83. data/lib/railroader/format/style.css +133 -0
  84. data/lib/railroader/options.rb +339 -0
  85. data/lib/railroader/parsers/rails2_erubis.rb +6 -0
  86. data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
  87. data/lib/railroader/parsers/rails3_erubis.rb +81 -0
  88. data/lib/railroader/parsers/template_parser.rb +108 -0
  89. data/lib/railroader/processor.rb +102 -0
  90. data/lib/railroader/processors/alias_processor.rb +1229 -0
  91. data/lib/railroader/processors/base_processor.rb +295 -0
  92. data/lib/railroader/processors/config_processor.rb +14 -0
  93. data/lib/railroader/processors/controller_alias_processor.rb +278 -0
  94. data/lib/railroader/processors/controller_processor.rb +249 -0
  95. data/lib/railroader/processors/erb_template_processor.rb +77 -0
  96. data/lib/railroader/processors/erubis_template_processor.rb +92 -0
  97. data/lib/railroader/processors/gem_processor.rb +64 -0
  98. data/lib/railroader/processors/haml_template_processor.rb +191 -0
  99. data/lib/railroader/processors/lib/basic_processor.rb +37 -0
  100. data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
  101. data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
  102. data/lib/railroader/processors/lib/find_call.rb +183 -0
  103. data/lib/railroader/processors/lib/find_return_value.rb +166 -0
  104. data/lib/railroader/processors/lib/module_helper.rb +111 -0
  105. data/lib/railroader/processors/lib/processor_helper.rb +88 -0
  106. data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
  107. data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
  108. data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
  109. data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
  110. data/lib/railroader/processors/lib/render_helper.rb +181 -0
  111. data/lib/railroader/processors/lib/render_path.rb +107 -0
  112. data/lib/railroader/processors/lib/route_helper.rb +68 -0
  113. data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
  114. data/lib/railroader/processors/library_processor.rb +74 -0
  115. data/lib/railroader/processors/model_processor.rb +91 -0
  116. data/lib/railroader/processors/output_processor.rb +144 -0
  117. data/lib/railroader/processors/route_processor.rb +17 -0
  118. data/lib/railroader/processors/slim_template_processor.rb +111 -0
  119. data/lib/railroader/processors/template_alias_processor.rb +118 -0
  120. data/lib/railroader/processors/template_processor.rb +85 -0
  121. data/lib/railroader/report/config/remediation.yml +71 -0
  122. data/lib/railroader/report/ignore/config.rb +153 -0
  123. data/lib/railroader/report/ignore/interactive.rb +362 -0
  124. data/lib/railroader/report/pager.rb +112 -0
  125. data/lib/railroader/report/renderer.rb +24 -0
  126. data/lib/railroader/report/report_base.rb +292 -0
  127. data/lib/railroader/report/report_codeclimate.rb +79 -0
  128. data/lib/railroader/report/report_csv.rb +55 -0
  129. data/lib/railroader/report/report_hash.rb +23 -0
  130. data/lib/railroader/report/report_html.rb +216 -0
  131. data/lib/railroader/report/report_json.rb +45 -0
  132. data/lib/railroader/report/report_markdown.rb +107 -0
  133. data/lib/railroader/report/report_table.rb +117 -0
  134. data/lib/railroader/report/report_tabs.rb +17 -0
  135. data/lib/railroader/report/report_text.rb +198 -0
  136. data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
  137. data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
  138. data/lib/railroader/report/templates/error_overview.html.erb +29 -0
  139. data/lib/railroader/report/templates/header.html.erb +58 -0
  140. data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
  141. data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
  142. data/lib/railroader/report/templates/overview.html.erb +38 -0
  143. data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
  144. data/lib/railroader/report/templates/template_overview.html.erb +21 -0
  145. data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
  146. data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
  147. data/lib/railroader/report.rb +88 -0
  148. data/lib/railroader/rescanner.rb +483 -0
  149. data/lib/railroader/scanner.rb +321 -0
  150. data/lib/railroader/tracker/collection.rb +93 -0
  151. data/lib/railroader/tracker/config.rb +154 -0
  152. data/lib/railroader/tracker/constants.rb +171 -0
  153. data/lib/railroader/tracker/controller.rb +161 -0
  154. data/lib/railroader/tracker/library.rb +17 -0
  155. data/lib/railroader/tracker/model.rb +90 -0
  156. data/lib/railroader/tracker/template.rb +33 -0
  157. data/lib/railroader/tracker.rb +362 -0
  158. data/lib/railroader/util.rb +503 -0
  159. data/lib/railroader/version.rb +3 -0
  160. data/lib/railroader/warning.rb +294 -0
  161. data/lib/railroader/warning_codes.rb +117 -0
  162. data/lib/railroader.rb +544 -0
  163. data/lib/ruby_parser/bm_sexp.rb +626 -0
  164. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  165. metadata +386 -0
@@ -0,0 +1,112 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ #sanitize and sanitize_css are vulnerable:
4
+ #CVE-2013-1855 and CVE-2013-1857
5
+ class Railroader::CheckSanitizeMethods < Railroader::BaseCheck
6
+ Railroader::Checks.add self
7
+
8
+ @description = "Checks for versions with vulnerable sanitize and sanitize_css"
9
+
10
+ def run_check
11
+ @fix_version = case
12
+ when version_between?('2.0.0', '2.3.17')
13
+ '2.3.18'
14
+ when version_between?('3.0.0', '3.0.99')
15
+ '3.2.13'
16
+ when version_between?('3.1.0', '3.1.11')
17
+ '3.1.12'
18
+ when version_between?('3.2.0', '3.2.12')
19
+ '3.2.13'
20
+ end
21
+
22
+ if @fix_version
23
+ check_cve_2013_1855
24
+ check_cve_2013_1857
25
+ end
26
+
27
+ if tracker.config.has_gem? :'rails-html-sanitizer'
28
+ check_rails_html_sanitizer
29
+ end
30
+
31
+ check_cve_2018_8048
32
+ end
33
+
34
+ def check_cve_2013_1855
35
+ check_for_cve :sanitize_css, :CVE_2013_1855, "https://groups.google.com/d/msg/rubyonrails-security/4_QHo4BqnN8/_RrdfKk12I4J"
36
+ end
37
+
38
+ def check_cve_2013_1857
39
+ check_for_cve :sanitize, :CVE_2013_1857, "https://groups.google.com/d/msg/rubyonrails-security/zAAU7vGTPvI/1vZDWXqBuXgJ"
40
+ end
41
+
42
+ def check_for_cve method, code, link
43
+ tracker.find_call(:target => false, :method => method).each do |result|
44
+ next if duplicate? result
45
+ add_result result
46
+
47
+ message = "Rails #{rails_version} has a vulnerability in #{method}: upgrade to #{@fix_version} or patch"
48
+
49
+ warn :result => result,
50
+ :warning_type => "Cross-Site Scripting",
51
+ :warning_code => code,
52
+ :message => message,
53
+ :confidence => :high,
54
+ :link_path => link
55
+ end
56
+ end
57
+
58
+ def check_rails_html_sanitizer
59
+ rhs_version = tracker.config.gem_version(:'rails-html-sanitizer')
60
+
61
+ if version_between? "1.0.0", "1.0.2", rhs_version
62
+ warn_sanitizer_cve "CVE-2015-7578", "https://groups.google.com/d/msg/rubyonrails-security/uh--W4TDwmI/JbvSRpdbFQAJ", "1.0.3"
63
+ warn_sanitizer_cve "CVE-2015-7580", "https://groups.google.com/d/msg/rubyonrails-security/uh--W4TDwmI/m_CVZtdbFQAJ", "1.0.3"
64
+ end
65
+
66
+ if version_between? "1.0.0", "1.0.3", rhs_version
67
+ warn_sanitizer_cve "CVE-2018-3741", "https://groups.google.com/d/msg/rubyonrails-security/tP7W3kLc5u4/uDy2Br7xBgAJ", "1.0.4"
68
+ end
69
+ end
70
+
71
+ def check_cve_2018_8048
72
+ if loofah_vulnerable_cve_2018_8048?
73
+ message = "Loofah #{tracker.config.gem_version(:loofah)} is vulnerable (CVE-2018-8048). Upgrade to 2.1.2"
74
+
75
+ if tracker.find_call(:target => false, :method => :sanitize).any?
76
+ confidence = :high
77
+ else
78
+ confidence = :medium
79
+ end
80
+
81
+ warn :warning_type => "Cross-Site Scripting",
82
+ :warning_code => :CVE_2018_8048,
83
+ :message => message,
84
+ :gem_info => gemfile_or_environment(:loofah),
85
+ :confidence => confidence,
86
+ :link_path => "https://github.com/flavorjones/loofah/issues/144"
87
+ end
88
+ end
89
+
90
+ def loofah_vulnerable_cve_2018_8048?
91
+ loofah_version = tracker.config.gem_version(:loofah)
92
+
93
+ loofah_version and loofah_version < "2.1.2"
94
+ end
95
+
96
+ def warn_sanitizer_cve cve, link, upgrade_version
97
+ message = "rails-html-sanitizer #{tracker.config.gem_version(:'rails-html-sanitizer')} is vulnerable (#{cve}). Upgrade to #{upgrade_version}"
98
+
99
+ if tracker.find_call(:target => false, :method => :sanitize).any?
100
+ confidence = :high
101
+ else
102
+ confidence = :medium
103
+ end
104
+
105
+ warn :warning_type => "Cross-Site Scripting",
106
+ :warning_code => cve.tr('-', '_').to_sym,
107
+ :message => message,
108
+ :gem_info => gemfile_or_environment(:'rails-html-sanitizer'),
109
+ :confidence => confidence,
110
+ :link_path => link
111
+ end
112
+ end
@@ -0,0 +1,40 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ class Railroader::CheckSecrets < Railroader::BaseCheck
4
+ Railroader::Checks.add_optional self
5
+
6
+ @description = "Checks for secrets stored in source code"
7
+
8
+ def run_check
9
+ check_constants
10
+ end
11
+
12
+ def check_constants
13
+ @warned = Set.new
14
+
15
+ @tracker.constants.each do |constant|
16
+ name = constant.name_array.last
17
+ value = constant.value
18
+
19
+ if string? value and not value.value.empty? and looks_like_secret? name
20
+ match = [name, value, value.line]
21
+
22
+ unless @warned.include? match
23
+ @warned << match
24
+
25
+ warn :warning_code => :secret_in_source,
26
+ :warning_type => "Authentication",
27
+ :message => "Hardcoded value for #{name} in source code",
28
+ :confidence => :medium,
29
+ :file => constant.file,
30
+ :line => constant.line
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def looks_like_secret? name
37
+ # REST_AUTH_SITE_KEY is the pepper in Devise
38
+ name.match /password|secret|(rest_auth_site|api)_key$/i
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ #Checks for CVE-2012-3463, unescaped input in :prompt option of select_tag:
4
+ #https://groups.google.com/d/topic/rubyonrails-security/fV3QUToSMSw/discussion
5
+ class Railroader::CheckSelectTag < Railroader::BaseCheck
6
+ Railroader::Checks.add self
7
+
8
+ @description = "Looks for unsafe uses of select_tag() in some versions of Rails 3.x"
9
+
10
+ def run_check
11
+
12
+ if version_between? "3.0.0", "3.0.16"
13
+ suggested_version = "3.0.17"
14
+ elsif version_between? "3.1.0", "3.1.7"
15
+ suggested_version = "3.1.8"
16
+ elsif version_between? "3.2.0", "3.2.7"
17
+ suggested_version = "3.2.8"
18
+ else
19
+ return
20
+ end
21
+
22
+ @ignore_methods = Set[:escapeHTML, :escape_once, :h].merge tracker.options[:safe_methods]
23
+
24
+ @message = "Upgrade to Rails #{suggested_version}, #{rails_version} select_tag is vulnerable (CVE-2012-3463)"
25
+
26
+ calls = tracker.find_call(:target => nil, :method => :select_tag).select do |result|
27
+ result[:location][:type] == :template
28
+ end
29
+
30
+ calls.each do |result|
31
+ process_result result
32
+ end
33
+ end
34
+
35
+ #Check if select_tag is called with user input in :prompt option
36
+ def process_result result
37
+ return unless original? result
38
+
39
+ #Only concerned if user input is supplied for :prompt option
40
+ last_arg = result[:call].last_arg
41
+
42
+ if hash? last_arg
43
+ prompt_option = hash_access last_arg, :prompt
44
+
45
+ if call? prompt_option and @ignore_methods.include? prompt_option.method
46
+ return
47
+ elsif sexp? prompt_option and input = include_user_input?(prompt_option)
48
+
49
+ warn :warning_type => "Cross-Site Scripting",
50
+ :warning_code => :CVE_2012_3463,
51
+ :result => result,
52
+ :message => @message,
53
+ :confidence => :high,
54
+ :user_input => input,
55
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/fV3QUToSMSw/discussion"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,60 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ #Checks for select() helper vulnerability in some versions of Rails 3
4
+ #http://groups.google.com/group/rubyonrails-security/browse_thread/thread/9da0c515a6c4664
5
+ class Railroader::CheckSelectVulnerability < Railroader::BaseCheck
6
+ Railroader::Checks.add self
7
+
8
+ @description = "Looks for unsafe uses of select() helper"
9
+
10
+ def run_check
11
+
12
+ if lts_version? "2.3.18.7"
13
+ return
14
+ elsif version_between? "3.0.0", "3.0.11"
15
+ suggested_version = "3.0.12"
16
+ elsif version_between? "3.1.0", "3.1.3"
17
+ suggested_version = "3.1.4"
18
+ elsif version_between? "3.2.0", "3.2.1"
19
+ suggested_version = "3.2.2"
20
+ elsif version_between? "2.0.0", "2.3.14"
21
+ suggested_version = "3 or use options_for_select"
22
+ else
23
+ return
24
+ end
25
+
26
+ @message = "Upgrade to Rails #{suggested_version}, #{rails_version} select() helper is vulnerable"
27
+
28
+ calls = tracker.find_call(:target => nil, :method => :select).select do |result|
29
+ result[:location][:type] == :template
30
+ end
31
+
32
+ calls.each do |result|
33
+ process_result result
34
+ end
35
+ end
36
+
37
+ def process_result result
38
+ return if duplicate? result
39
+
40
+ third_arg = result[:call].third_arg
41
+
42
+ #Check for user input in options parameter
43
+ if sexp? third_arg and include_user_input? third_arg
44
+ add_result result
45
+
46
+ if string_interp? third_arg
47
+ confidence = :medium
48
+ else
49
+ confidence = :weak
50
+ end
51
+
52
+ warn :template => result[:location][:template],
53
+ :warning_type => "Cross-Site Scripting",
54
+ :warning_code => :select_options_vuln,
55
+ :result => result,
56
+ :message => @message,
57
+ :confidence => confidence
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,47 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ #Checks if user supplied data is passed to send
4
+ class Railroader::CheckSend < Railroader::BaseCheck
5
+ Railroader::Checks.add self
6
+
7
+ @description = "Check for unsafe use of Object#send"
8
+
9
+ def run_check
10
+ @send_methods = [:send, :try, :__send__, :public_send]
11
+ Railroader.debug("Finding instances of #send")
12
+ calls = tracker.find_call :methods => @send_methods, :nested => true
13
+
14
+ calls.each do |call|
15
+ process_result call
16
+ end
17
+ end
18
+
19
+ def process_result result
20
+ return unless original? result
21
+
22
+ send_call = get_send result[:call]
23
+ process_call_args send_call
24
+ process send_call.target
25
+
26
+ if input = has_immediate_user_input?(send_call.first_arg)
27
+ warn :result => result,
28
+ :warning_type => "Dangerous Send",
29
+ :warning_code => :dangerous_send,
30
+ :message => "User controlled method execution",
31
+ :code => result[:call],
32
+ :user_input => input,
33
+ :confidence => :high
34
+ end
35
+ end
36
+
37
+ # Recursively check call chain for send call
38
+ def get_send exp
39
+ if call? exp
40
+ if @send_methods.include? exp.method
41
+ return exp
42
+ else
43
+ get_send exp.target
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ require 'railroader/checks/check_file_access'
2
+ require 'railroader/processors/lib/processor_helper'
3
+
4
+ #Checks for user input in send_file()
5
+ class Railroader::CheckSendFile < Railroader::CheckFileAccess
6
+ Railroader::Checks.add self
7
+
8
+ @description = "Check for user input in uses of send_file"
9
+
10
+ def run_check
11
+ Railroader.debug "Finding all calls to send_file()"
12
+
13
+ methods = tracker.find_call :target => false, :method => :send_file
14
+
15
+ methods.each do |call|
16
+ process_result call
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ class Railroader::CheckSessionManipulation < Railroader::BaseCheck
4
+ Railroader::Checks.add self
5
+
6
+ @description = "Check for user input in session keys"
7
+
8
+ def run_check
9
+ tracker.find_call(:method => :[]=, :target => :session).each do |result|
10
+ process_result result
11
+ end
12
+ end
13
+
14
+ def process_result result
15
+ return unless original? result
16
+
17
+ index = result[:call].first_arg
18
+
19
+ if input = has_immediate_user_input?(index)
20
+ if params? index
21
+ confidence = :high
22
+ else
23
+ confidence = :medium
24
+ end
25
+
26
+ warn :result => result,
27
+ :warning_type => "Session Manipulation",
28
+ :warning_code => :session_key_manipulation,
29
+ :message => "#{friendly_type_of(input).capitalize} used as key in session hash",
30
+ :code => result[:call],
31
+ :user_input => input,
32
+ :confidence => confidence
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,176 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ #Checks for session key length and http_only settings
4
+ class Railroader::CheckSessionSettings < Railroader::BaseCheck
5
+ Railroader::Checks.add self
6
+
7
+ @description = "Checks for session key length and http_only settings"
8
+
9
+ def initialize *args
10
+ super
11
+
12
+ unless tracker.options[:rails3]
13
+ @session_settings = Sexp.new(:colon2, Sexp.new(:const, :ActionController), :Base)
14
+ else
15
+ @session_settings = nil
16
+ end
17
+ end
18
+
19
+ def run_check
20
+ settings = tracker.config.session_settings
21
+
22
+ check_for_issues settings, @app_tree.expand_path("config/environment.rb")
23
+
24
+ ["session_store.rb", "secret_token.rb"].each do |file|
25
+ if tracker.initializers[file] and not ignored? file
26
+ process tracker.initializers[file]
27
+ end
28
+ end
29
+
30
+ if tracker.options[:rails4]
31
+ check_secrets_yaml
32
+ end
33
+ end
34
+
35
+ #Looks for ActionController::Base.session = { ... }
36
+ #in Rails 2.x apps
37
+ #
38
+ #and App::Application.config.secret_token =
39
+ #in Rails 3.x apps
40
+ #
41
+ #and App::Application.config.secret_key_base =
42
+ #in Rails 4.x apps
43
+ def process_attrasgn exp
44
+ if not tracker.options[:rails3] and exp.target == @session_settings and exp.method == :session=
45
+ check_for_issues exp.first_arg, @app_tree.expand_path("config/initializers/session_store.rb")
46
+ end
47
+
48
+ if tracker.options[:rails3] and settings_target?(exp.target) and
49
+ (exp.method == :secret_token= or exp.method == :secret_key_base=) and string? exp.first_arg
50
+
51
+ warn_about_secret_token exp.line, @app_tree.expand_path("config/initializers/secret_token.rb")
52
+ end
53
+
54
+ exp
55
+ end
56
+
57
+ #Looks for Rails3::Application.config.session_store :cookie_store, { ... }
58
+ #in Rails 3.x apps
59
+ def process_call exp
60
+ if tracker.options[:rails3] and settings_target?(exp.target) and exp.method == :session_store
61
+ check_for_rails3_issues exp.second_arg, @app_tree.expand_path("config/initializers/session_store.rb")
62
+ end
63
+
64
+ exp
65
+ end
66
+
67
+ private
68
+
69
+ def settings_target? exp
70
+ call? exp and
71
+ exp.method == :config and
72
+ node_type? exp.target, :colon2 and
73
+ exp.target.rhs == :Application
74
+ end
75
+
76
+ def check_for_issues settings, file
77
+ if settings and hash? settings
78
+ if value = (hash_access(settings, :session_http_only) ||
79
+ hash_access(settings, :http_only) ||
80
+ hash_access(settings, :httponly))
81
+
82
+ if false? value
83
+ warn_about_http_only value.line, file
84
+ end
85
+ end
86
+
87
+ if value = hash_access(settings, :secret)
88
+ if string? value
89
+ warn_about_secret_token value.line, file
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ def check_for_rails3_issues settings, file
96
+ if settings and hash? settings
97
+ if value = hash_access(settings, :httponly)
98
+ if false? value
99
+ warn_about_http_only value.line, file
100
+ end
101
+ end
102
+
103
+ if value = hash_access(settings, :secure)
104
+ if false? value
105
+ warn_about_secure_only value.line, file
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def check_secrets_yaml
112
+ secrets_file = "config/secrets.yml"
113
+
114
+ if @app_tree.exists? secrets_file and not ignored? "secrets.yml" and not ignored? "config/*.yml"
115
+ yaml = @app_tree.read secrets_file
116
+ require 'date' # https://github.com/dtao/safe_yaml/issues/80
117
+ require 'safe_yaml/load'
118
+ begin
119
+ secrets = SafeYAML.load yaml
120
+ rescue Psych::SyntaxError, RuntimeError => e
121
+ Railroader.notify "[Notice] #{self.class}: Unable to parse `#{secrets_file}`"
122
+ Railroader.debug "Failed to parse #{secrets_file}: #{e.inspect}"
123
+ return
124
+ end
125
+
126
+ if secrets["production"] and secret = secrets["production"]["secret_key_base"]
127
+ unless secret.include? "<%="
128
+ line = yaml.lines.find_index { |l| l.include? secret } + 1
129
+
130
+ warn_about_secret_token line, @app_tree.expand_path(secrets_file)
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ def warn_about_http_only line, file
137
+ warn :warning_type => "Session Setting",
138
+ :warning_code => :http_cookies,
139
+ :message => "Session cookies should be set to HTTP only",
140
+ :confidence => :high,
141
+ :line => line,
142
+ :file => file
143
+
144
+ end
145
+
146
+ def warn_about_secret_token line, file
147
+ warn :warning_type => "Session Setting",
148
+ :warning_code => :session_secret,
149
+ :message => "Session secret should not be included in version control",
150
+ :confidence => :high,
151
+ :line => line,
152
+ :file => file
153
+ end
154
+
155
+ def warn_about_secure_only line, file
156
+ warn :warning_type => "Session Setting",
157
+ :warning_code => :secure_cookies,
158
+ :message => "Session cookie should be set to secure only",
159
+ :confidence => :high,
160
+ :line => line,
161
+ :file => file
162
+ end
163
+
164
+ def ignored? file
165
+ [".", "config", "config/initializers"].each do |dir|
166
+ ignore_file = "#{dir}/.gitignore"
167
+ if @app_tree.exists? ignore_file
168
+ input = @app_tree.read(ignore_file)
169
+
170
+ return true if input.include? file
171
+ end
172
+ end
173
+
174
+ false
175
+ end
176
+ end
@@ -0,0 +1,58 @@
1
+ require 'railroader/checks/base_check'
2
+
3
+ class Railroader::CheckSimpleFormat < Railroader::CheckCrossSiteScripting
4
+ Railroader::Checks.add self
5
+
6
+ @description = "Checks for simple_format XSS vulnerability (CVE-2013-6416) in certain versions"
7
+
8
+ def run_check
9
+ if version_between? "4.0.0", "4.0.1"
10
+ @inspect_arguments = true
11
+ @ignore_methods = Set[:h, :escapeHTML]
12
+
13
+ check_simple_format_usage
14
+ generic_warning unless @found_any
15
+ end
16
+ end
17
+
18
+ def generic_warning
19
+ message = "Rails #{rails_version} has a vulnerability in simple_format (CVE-2013-6416). Upgrade to Rails version 4.0.2"
20
+
21
+ warn :warning_type => "Cross-Site Scripting",
22
+ :warning_code => :CVE_2013_6416,
23
+ :message => message,
24
+ :confidence => :medium,
25
+ :gem_info => gemfile_or_environment,
26
+ :link_path => "https://groups.google.com/d/msg/ruby-security-ann/5ZI1-H5OoIM/ZNq4FoR2GnIJ"
27
+ end
28
+
29
+ def check_simple_format_usage
30
+ tracker.find_call(:target => false, :method => :simple_format).each do |result|
31
+ @matched = false
32
+ process_call result[:call]
33
+ if @matched
34
+ warn_on_simple_format result, @matched
35
+ end
36
+ end
37
+ end
38
+
39
+ def process_call exp
40
+ @mark = true
41
+ actually_process_call exp
42
+ exp
43
+ end
44
+
45
+ def warn_on_simple_format result, match
46
+ return unless original? result
47
+
48
+ @found_any = true
49
+
50
+ warn :result => result,
51
+ :warning_type => "Cross-Site Scripting",
52
+ :warning_code => :CVE_2013_6416_call,
53
+ :message => "Values passed to simple_format are not safe in Rails #{rails_version}",
54
+ :confidence => :high,
55
+ :link_path => "https://groups.google.com/d/msg/ruby-security-ann/5ZI1-H5OoIM/ZNq4FoR2GnIJ",
56
+ :user_input => match
57
+ end
58
+ end