brakeman-lib 3.3.1

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 (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,116 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #Reports any calls to +validates_format_of+ which do not use +\A+ and +\z+
4
+ #as anchors in the given regular expression.
5
+ #
6
+ #For example:
7
+ #
8
+ # #Allows anything after new line
9
+ # validates_format_of :user_name, :with => /^\w+$/
10
+ class Brakeman::CheckValidationRegex < Brakeman::BaseCheck
11
+ Brakeman::Checks.add self
12
+
13
+ @description = "Report uses of validates_format_of with improper anchors"
14
+
15
+ WITH = Sexp.new(:lit, :with)
16
+ FORMAT = Sexp.new(:lit, :format)
17
+
18
+ def run_check
19
+ active_record_models.each do |name, model|
20
+ @current_model = name
21
+ format_validations = model.options[:validates_format_of]
22
+
23
+ if format_validations
24
+ format_validations.each do |v|
25
+ process_validates_format_of v
26
+ end
27
+ end
28
+
29
+ validates = model.options[:validates]
30
+
31
+ if validates
32
+ validates.each do |v|
33
+ process_validates v
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ #Check validates_format_of
40
+ def process_validates_format_of validator
41
+ if value = hash_access(validator.last, WITH)
42
+ check_regex value, validator
43
+ end
44
+ end
45
+
46
+ #Check validates ..., :format => ...
47
+ def process_validates validator
48
+ hash_arg = validator.last
49
+ return unless hash? hash_arg
50
+
51
+ value = hash_access(hash_arg, FORMAT)
52
+
53
+ if hash? value
54
+ value = hash_access(value, WITH)
55
+ end
56
+
57
+ if value
58
+ check_regex value, validator
59
+ end
60
+ end
61
+
62
+ # Match secure regexp without extended option
63
+ SECURE_REGEXP_PATTERN = %r{
64
+ \A
65
+ \\A
66
+ .*
67
+ \\[zZ]
68
+ \z
69
+ }x
70
+
71
+ # Match secure of regexp with extended option
72
+ EXTENDED_SECURE_REGEXP_PATTERN = %r{
73
+ \A
74
+ \s*
75
+ \\A
76
+ .*
77
+ \\[zZ]
78
+ \s*
79
+ \z
80
+ }mx
81
+
82
+ #Issue warning if the regular expression does not use
83
+ #+\A+ and +\z+
84
+ def check_regex value, validator
85
+ return unless regexp? value
86
+
87
+ regex = value.value
88
+ unless secure_regex?(regex)
89
+ warn :model => @current_model,
90
+ :warning_type => "Format Validation",
91
+ :warning_code => :validation_regex,
92
+ :message => "Insufficient validation for '#{get_name validator}' using #{regex.inspect}. Use \\A and \\z as anchors",
93
+ :line => value.line,
94
+ :confidence => CONFIDENCE[:high]
95
+ end
96
+ end
97
+
98
+ #Get the name of the attribute being validated.
99
+ def get_name validator
100
+ name = validator[1]
101
+
102
+ if sexp? name
103
+ name.value
104
+ else
105
+ name
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def secure_regex?(regex)
112
+ extended_regex = Regexp::EXTENDED == regex.options & Regexp::EXTENDED
113
+ regex_pattern = extended_regex ? EXTENDED_SECURE_REGEXP_PATTERN : SECURE_REGEXP_PATTERN
114
+ regex_pattern =~ regex.source
115
+ end
116
+ end
@@ -0,0 +1,151 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckWeakHash < Brakeman::BaseCheck
4
+ Brakeman::Checks.add_optional self
5
+
6
+ @description = "Checks for use of weak hashes like MD5"
7
+
8
+ DIGEST_CALLS = [:base64digest, :digest, :hexdigest, :new]
9
+
10
+ def run_check
11
+ tracker.find_call(:targets => [:'Digest::MD5', :'Digest::SHA1', :'OpenSSL::Digest::MD5', :'OpenSSL::Digest::SHA1'], :nested => true).each do |result|
12
+ process_hash_result result
13
+ end
14
+
15
+ tracker.find_call(:target => :'Digest::HMAC', :methods => [:new, :hexdigest], :nested => true).each do |result|
16
+ process_hmac_result result
17
+ end
18
+
19
+ tracker.find_call(:targets => [:'OpenSSL::Digest::Digest', :'OpenSSL::Digest'], :method => :new).each do |result|
20
+ process_openssl_result result
21
+ end
22
+ end
23
+
24
+ def process_hash_result result
25
+ return if duplicate? result
26
+ add_result result
27
+
28
+ input = nil
29
+ call = result[:call]
30
+
31
+ if DIGEST_CALLS.include? call.method
32
+ if input = user_input_as_arg?(call)
33
+ confidence = CONFIDENCE[:high]
34
+ elsif input = hashing_password?(call)
35
+ confidence = CONFIDENCE[:high]
36
+ else
37
+ confidence = CONFIDENCE[:med]
38
+ end
39
+ else
40
+ confidence = CONFIDENCE[:med]
41
+ end
42
+
43
+
44
+ alg = case call.target.last
45
+ when :MD5
46
+ " (MD5)"
47
+ when :SHA1
48
+ " (SHA1)"
49
+ else
50
+ ""
51
+ end
52
+
53
+ warn :result => result,
54
+ :warning_type => "Weak Hash",
55
+ :warning_code => :weak_hash_digest,
56
+ :message => "Weak hashing algorithm#{alg} used",
57
+ :confidence => confidence,
58
+ :user_input => input
59
+ end
60
+
61
+ def process_hmac_result result
62
+ return if duplicate? result
63
+ add_result result
64
+
65
+ call = result[:call]
66
+
67
+ alg = case call.third_arg.last
68
+ when :MD5
69
+ 'MD5'
70
+ when :SHA1
71
+ 'SHA1'
72
+ else
73
+ return
74
+ end
75
+
76
+ warn :result => result,
77
+ :warning_type => "Weak Hash",
78
+ :warning_code => :weak_hash_hmac,
79
+ :message => "Weak hashing algorithm (#{alg}) used in HMAC",
80
+ :confidence => CONFIDENCE[:med]
81
+ end
82
+
83
+ def process_openssl_result result
84
+ return if duplicate? result
85
+ add_result result
86
+
87
+ arg = result[:call].first_arg
88
+
89
+ if string? arg
90
+ alg = arg.value.upcase
91
+
92
+ if alg == 'MD5' or alg == 'SHA1'
93
+ warn :result => result,
94
+ :warning_type => "Weak Hash",
95
+ :warning_code => :weak_hash_digest,
96
+ :message => "Weak hashing algorithm (#{alg}) used",
97
+ :confidence => CONFIDENCE[:med]
98
+ end
99
+ end
100
+ end
101
+
102
+ def user_input_as_arg? call
103
+ call.each_arg do |arg|
104
+ if input = include_user_input?(arg)
105
+ return input
106
+ end
107
+ end
108
+
109
+ nil
110
+ end
111
+
112
+ def hashing_password? call
113
+ call.each_arg do |arg|
114
+ @has_password = false
115
+
116
+ process arg
117
+
118
+ if @has_password
119
+ return @has_password
120
+ end
121
+ end
122
+
123
+ nil
124
+ end
125
+
126
+ def process_call exp
127
+ if exp.method == :password
128
+ @has_password = exp
129
+ else
130
+ process_default exp
131
+ end
132
+
133
+ exp
134
+ end
135
+
136
+ def process_ivar exp
137
+ if exp.value == :@password
138
+ @has_password = exp
139
+ end
140
+
141
+ exp
142
+ end
143
+
144
+ def process_lvar exp
145
+ if exp.value == :password
146
+ @has_password = exp
147
+ end
148
+
149
+ exp
150
+ end
151
+ end
@@ -0,0 +1,80 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #Check for bypassing mass assignment protection
4
+ #with without_protection => true
5
+ #
6
+ #Only for Rails 3.1
7
+ class Brakeman::CheckWithoutProtection < Brakeman::BaseCheck
8
+ Brakeman::Checks.add self
9
+
10
+ @description = "Check for mass assignment using without_protection"
11
+
12
+ def run_check
13
+ if version_between? "0.0.0", "3.0.99"
14
+ return
15
+ end
16
+
17
+ return if active_record_models.empty?
18
+
19
+ Brakeman.debug "Finding all mass assignments"
20
+ calls = tracker.find_call :targets => active_record_models.keys, :methods => [:new,
21
+ :attributes=,
22
+ :update_attributes,
23
+ :update_attributes!,
24
+ :create,
25
+ :create!]
26
+
27
+ Brakeman.debug "Processing all mass assignments"
28
+ calls.each do |result|
29
+ process_result result
30
+ end
31
+ end
32
+
33
+ #All results should be Model.new(...) or Model.attributes=() calls
34
+ def process_result res
35
+ call = res[:call]
36
+ last_arg = call.last_arg
37
+
38
+ if hash? last_arg and not call.original_line and not duplicate? res
39
+
40
+ if value = hash_access(last_arg, :without_protection)
41
+ if true? value
42
+ add_result res
43
+
44
+ if input = include_user_input?(call.arglist)
45
+ confidence = CONFIDENCE[:high]
46
+ elsif all_literals? call
47
+ return
48
+ else
49
+ confidence = CONFIDENCE[:med]
50
+ end
51
+
52
+ warn :result => res,
53
+ :warning_type => "Mass Assignment",
54
+ :warning_code => :mass_assign_without_protection,
55
+ :message => "Unprotected mass assignment",
56
+ :code => call,
57
+ :user_input => input,
58
+ :confidence => confidence
59
+
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def all_literals? call
66
+ call.each_arg do |arg|
67
+ if hash? arg
68
+ hash_iterate arg do |k, v|
69
+ unless node_type? k, :str, :lit, :false, :true and node_type? v, :str, :lit, :false, :true
70
+ return false
71
+ end
72
+ end
73
+ else
74
+ return false
75
+ end
76
+ end
77
+
78
+ true
79
+ end
80
+ end
@@ -0,0 +1,51 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckXMLDoS < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for XML denial of service (CVE-2015-3227)"
7
+
8
+ def run_check
9
+ version = rails_version
10
+
11
+ fix_version = case
12
+ when version_between?("2.0.0", "3.2.21")
13
+ "3.2.22"
14
+ when version_between?("4.1.0", "4.1.10")
15
+ "4.1.11"
16
+ when version_between?("4.2.0", "4.2.1")
17
+ "4.2.2"
18
+ when version_between?("4.0.0", "4.0.99")
19
+ "4.2.2"
20
+ when (version.nil? and tracker.options[:rails3])
21
+ version = "3.x"
22
+ "3.2.22"
23
+ when (version.nil? and tracker.options[:rails4])
24
+ version = "4.x"
25
+ "4.2.2"
26
+ else
27
+ return
28
+ end
29
+
30
+ return if has_workaround?
31
+
32
+ message = "Rails #{version} is vulnerable to denial of service via XML parsing (CVE-2015-3227). Upgrade to Rails version #{fix_version}"
33
+
34
+ warn :warning_type => "Denial of Service",
35
+ :warning_code => :CVE_2015_3227,
36
+ :message => message,
37
+ :confidence => CONFIDENCE[:med],
38
+ :gem_info => gemfile_or_environment,
39
+ :link_path => "https://groups.google.com/d/msg/rubyonrails-security/bahr2JLnxvk/x4EocXnHPp8J"
40
+ end
41
+
42
+ def has_workaround?
43
+ tracker.check_initializers(:"ActiveSupport::XmlMini", :backend=).any? do |match|
44
+ arg = match.call.first_arg
45
+ if string? arg
46
+ value = arg.value
47
+ value == 'Nokogiri' or value == 'LibXML'
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,121 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckYAMLParsing < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for YAML parsing vulnerabilities (CVE-2013-0156)"
7
+
8
+ def run_check
9
+ return unless version_between? "0.0.0", "2.3.14" or
10
+ version_between? "3.0.0", "3.0.18" or
11
+ version_between? "3.1.0", "3.1.9" or
12
+ version_between? "3.2.0", "3.2.10"
13
+
14
+ unless disabled_xml_parser? or disabled_xml_dangerous_types?
15
+ new_version = if version_between? "0.0.0", "2.3.14"
16
+ "2.3.15"
17
+ elsif version_between? "3.0.0", "3.0.18"
18
+ "3.0.19"
19
+ elsif version_between? "3.1.0", "3.1.9"
20
+ "3.1.10"
21
+ elsif version_between? "3.2.0", "3.2.10"
22
+ "3.2.11"
23
+ end
24
+
25
+ message = "Rails #{rails_version} has a remote code execution vulnerability: upgrade to #{new_version} or disable XML parsing"
26
+
27
+ warn :warning_type => "Remote Code Execution",
28
+ :warning_code => :CVE_2013_0156,
29
+ :message => message,
30
+ :confidence => CONFIDENCE[:high],
31
+ :gem_info => gemfile_or_environment,
32
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/61bkgvnSGTQ/discussion"
33
+ end
34
+
35
+ #Warn if app accepts YAML
36
+ if version_between?("0.0.0", "2.3.14") and enabled_yaml_parser?
37
+ message = "Parsing YAML request parameters enables remote code execution: disable YAML parser"
38
+
39
+ warn :warning_type => "Remote Code Execution",
40
+ :warning_code => :CVE_2013_0156,
41
+ :message => message,
42
+ :confidence => CONFIDENCE[:high],
43
+ :gem_info => gemfile_or_environment,
44
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/61bkgvnSGTQ/discussion"
45
+ end
46
+ end
47
+
48
+ def disabled_xml_parser?
49
+ if version_between? "0.0.0", "2.3.14"
50
+ #Look for ActionController::Base.param_parsers.delete(Mime::XML)
51
+ params_parser = s(:call,
52
+ s(:colon2, s(:const, :ActionController), :Base),
53
+ :param_parsers)
54
+
55
+ matches = tracker.check_initializers(params_parser, :delete)
56
+ else
57
+ #Look for ActionDispatch::ParamsParser::DEFAULT_PARSERS.delete(Mime::XML)
58
+ matches = tracker.check_initializers(:"ActionDispatch::ParamsParser::DEFAULT_PARSERS", :delete)
59
+ end
60
+
61
+ unless matches.empty?
62
+ mime_xml = s(:colon2, s(:const, :Mime), :XML)
63
+
64
+ matches.each do |result|
65
+ if result.call.first_arg == mime_xml
66
+ return true
67
+ end
68
+ end
69
+ end
70
+
71
+ false
72
+ end
73
+
74
+ #Look for ActionController::Base.param_parsers[Mime::YAML] = :yaml
75
+ #in Rails 2.x apps
76
+ def enabled_yaml_parser?
77
+ param_parsers = s(:call,
78
+ s(:colon2, s(:const, :ActionController), :Base),
79
+ :param_parsers)
80
+
81
+ matches = tracker.check_initializers(param_parsers, :[]=)
82
+
83
+ mime_yaml = s(:colon2, s(:const, :Mime), :YAML)
84
+
85
+ matches.each do |result|
86
+ if result.call.first_arg == mime_yaml and
87
+ symbol? result.call.second_arg and
88
+ result.call.second_arg.value == :yaml
89
+
90
+ return true
91
+ end
92
+ end
93
+
94
+ false
95
+ end
96
+
97
+ def disabled_xml_dangerous_types?
98
+ if version_between? "0.0.0", "2.3.14"
99
+ matches = tracker.check_initializers(:"ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING", :delete)
100
+ else
101
+ matches = tracker.check_initializers(:"ActiveSupport::XmlMini::PARSING", :delete)
102
+ end
103
+
104
+ symbols_off = false
105
+ yaml_off = false
106
+
107
+ matches.each do |result|
108
+ arg = result.call.first_arg
109
+
110
+ if string? arg
111
+ if arg.value == "yaml"
112
+ yaml_off = true
113
+ elsif arg.value == "symbol"
114
+ symbols_off = true
115
+ end
116
+ end
117
+ end
118
+
119
+ symbols_off and yaml_off
120
+ end
121
+ end