brakeman 1.9.1 → 1.9.2

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.
data/CHANGES CHANGED
@@ -1,3 +1,14 @@
1
+ # 1.9.2
2
+
3
+ * Add check for CVE-2013-0269
4
+ * Add check for CVE-2013-0276
5
+ * Add check for CVE-2013-0277
6
+ * Add check for CVE-2013-0333
7
+ * Check for more send-like methods
8
+ * Check for more SQL injection locations
9
+ * Check for more dangerous YAML methods
10
+ * Support MultiJSON 1.2 for Rails 3.0 and 3.1
11
+
1
12
  # 1.9.1
2
13
 
3
14
  * Update to RubyParser 3.1.1 (neersighted)
@@ -23,7 +23,9 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
23
23
  @string_interp = false
24
24
  @current_set = nil
25
25
  @current_template = @current_module = @current_class = @current_method = nil
26
+ @active_record_models = nil
26
27
  @mass_assign_disabled = nil
28
+ @has_user_input = nil
27
29
  @safe_input_attributes = Set[:to_i, :to_f, :arel_table]
28
30
  end
29
31
 
@@ -32,6 +32,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
32
32
 
33
33
  @models = tracker.models.keys
34
34
  @inspect_arguments = tracker.options[:check_arguments]
35
+ @mark = nil
35
36
 
36
37
  Brakeman.debug "Checking for XSS in content_tag"
37
38
  methods.each do |call|
@@ -158,7 +159,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
158
159
  :user_input => @matched.match,
159
160
  :confidence => CONFIDENCE[:med],
160
161
  :link_path => "content_tag"
161
- end
162
+ end
162
163
  end
163
164
 
164
165
  def process_call exp
@@ -0,0 +1,100 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckJSONParsing < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for JSON parsing vulnerabilities CVE-2013-0333 and CVE-2013-0269"
7
+
8
+ def run_check
9
+ check_cve_2013_0333
10
+ check_cve_2013_0269
11
+ end
12
+
13
+ def check_cve_2013_0333
14
+ return unless version_between? "0.0.0", "2.3.15" or version_between? "3.0.0", "3.0.19"
15
+
16
+ unless uses_yajl? or uses_gem_backend?
17
+ new_version = if version_between? "0.0.0", "2.3.14"
18
+ "2.3.16"
19
+ elsif version_between? "3.0.0", "3.0.19"
20
+ "3.0.20"
21
+ end
22
+
23
+ message = "Rails #{tracker.config[:rails_version]} has a serious JSON parsing vulnerability: upgrade to #{new_version} or patch"
24
+
25
+ warn :warning_type => "Remote Code Execution",
26
+ :message => message,
27
+ :confidence => CONFIDENCE[:high],
28
+ :file => gemfile_or_environment,
29
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/1h2DR63ViGo/discussion"
30
+ end
31
+ end
32
+
33
+ #Check if `yajl` is included in Gemfile
34
+ def uses_yajl?
35
+ tracker.config[:gems] and tracker.config[:gems][:yajl]
36
+ end
37
+
38
+ #Check for `ActiveSupport::JSON.backend = "JSONGem"`
39
+ def uses_gem_backend?
40
+ matches = tracker.check_initializers(:'ActiveSupport::JSON', :backend=)
41
+
42
+ unless matches.empty?
43
+ json_gem = s(:str, "JSONGem")
44
+
45
+ matches.each do |result|
46
+ if result.call.first_arg == json_gem
47
+ return true
48
+ end
49
+ end
50
+ end
51
+
52
+ false
53
+ end
54
+
55
+ def check_cve_2013_0269
56
+ [:json, :json_pure].each do |name|
57
+ version = tracker.config[:gems] && tracker.config[:gems][name]
58
+ check_json_version name, version if version
59
+ end
60
+ end
61
+
62
+ def check_json_version name, version
63
+ return if version >= "1.7.7" or
64
+ (version >= "1.6.8" and version < "1.7.0") or
65
+ (version >= "1.5.5" and version < "1.6.0")
66
+
67
+ warning_type = "Denial of Service"
68
+ confidence = CONFIDENCE[:med]
69
+ message = "#{name} gem version #{version} has a symbol creation vulnerablity: upgrade to "
70
+
71
+ if version >= "1.7.0"
72
+ confidence = CONFIDENCE[:high]
73
+ warning_type = "Remote Code Execution"
74
+ message = "#{name} gem version #{version} has a remote code vulnerablity: upgrade to 1.7.7"
75
+ elsif version >= "1.6.0"
76
+ message << "1.6.8"
77
+ elsif version >= "1.5.0"
78
+ message << "1.5.5"
79
+ else
80
+ confidence = CONFIDENCE[:low]
81
+ message << "1.5.5"
82
+ end
83
+
84
+ if confidence == CONFIDENCE[:med] and uses_json_parse?
85
+ confidence = CONFIDENCE[:high]
86
+ end
87
+
88
+ warn :warning_type => warning_type,
89
+ :message => message,
90
+ :confidence => confidence,
91
+ :file => gemfile_or_environment,
92
+ :link => "https://groups.google.com/d/topic/rubyonrails-security/4_YvCpLzL58/discussion"
93
+ end
94
+
95
+ def uses_json_parse?
96
+ return @uses_json_parse unless @uses_json_parse.nil?
97
+
98
+ not tracker.find_call(:target => :JSON, :method => :parse).empty?
99
+ end
100
+ end
@@ -34,10 +34,13 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
34
34
  end
35
35
 
36
36
  unless protected_names.empty?
37
+ message, confidence, link = check_for_attr_protected_bypass
38
+
37
39
  warn :model => protected_names.sort.join(", "),
38
40
  :warning_type => "Attribute Restriction",
39
- :message => "attr_accessible is recommended over attr_protected",
40
- :confidence => CONFIDENCE[:low]
41
+ :message => message,
42
+ :confidence => confidence,
43
+ :link => link
41
44
  end
42
45
  else #Output one warning per model
43
46
 
@@ -49,12 +52,14 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
49
52
  :message => "Mass assignment is not restricted using attr_accessible",
50
53
  :confidence => CONFIDENCE[:high]
51
54
  elsif not tracker.options[:ignore_attr_protected]
55
+ message, confidence, link = check_for_attr_protected_bypass
56
+
52
57
  warn :model => name,
53
58
  :file => model[:file],
54
59
  :line => model[:options][:attr_protected].first.line,
55
60
  :warning_type => "Attribute Restriction",
56
- :message => "attr_accessible is recommended over attr_protected",
57
- :confidence => CONFIDENCE[:low]
61
+ :message => message,
62
+ :confidence => confidence
58
63
  end
59
64
  end
60
65
  end
@@ -67,4 +72,31 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
67
72
  end
68
73
  end
69
74
  end
75
+
76
+ def check_for_attr_protected_bypass
77
+ upgrade_version = case
78
+ when version_between?("2.0.0", "2.3.16")
79
+ "2.3.17"
80
+ when version_between?("3.0.0", "3.0.99")
81
+ "3.2.11"
82
+ when version_between?("3.1.0", "3.1.10")
83
+ "3.1.11"
84
+ when version_between?("3.2.0", "3.2.11")
85
+ "3.2.12"
86
+ else
87
+ nil
88
+ end
89
+
90
+ if upgrade_version
91
+ message = "attr_protected is bypassable in #{tracker.config[:rails_version]}, use attr_accessible or upgrade to #{upgrade_version}"
92
+ confidence = CONFIDENCE[:high]
93
+ link = "https://groups.google.com/d/topic/rubyonrails-security/AFBKNY7VSH8/discussion"
94
+ else
95
+ message = "attr_accessible is recommended over attr_protected"
96
+ confidence = CONFIDENCE[:med]
97
+ link = nil
98
+ end
99
+
100
+ return message, confidence, link
101
+ end
70
102
  end
@@ -0,0 +1,64 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckModelSerialize < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Report uses of serialize in versions vulnerable to CVE-2013-0277"
7
+
8
+ def run_check
9
+ @upgrade_version = case
10
+ when version_between?("2.0.0", "2.3.16")
11
+ "2.3.17"
12
+ when version_between?("3.0.0", "3.0.99")
13
+ "3.2.11"
14
+ else
15
+ nil
16
+ end
17
+
18
+ return unless @upgrade_version
19
+
20
+ tracker.models.each do |name, model|
21
+ check_for_serialize model
22
+ end
23
+ end
24
+
25
+ #High confidence warning on serialized, unprotected attributes.
26
+ #Medium confidence warning for serialized, protected attributes.
27
+ def check_for_serialize model
28
+ if serialized_attrs = model[:options] && model[:options][:serialize]
29
+ attrs = Set.new
30
+
31
+ serialized_attrs.each do |arglist|
32
+ arglist.each do |arg|
33
+ attrs << arg if symbol? arg
34
+ end
35
+ end
36
+
37
+ if unsafe_attrs = model[:attr_accessible]
38
+ attrs.delete_if { |attr| not unsafe_attrs.include? attr.value }
39
+ elsif protected_attrs = model[:options][:attr_protected]
40
+ safe_attrs = Set.new
41
+
42
+ protected_attrs.each do |arglist|
43
+ arglist.each do |arg|
44
+ safe_attrs << arg if symbol? arg
45
+ end
46
+ end
47
+
48
+ attrs.delete_if { |attr| safe_attrs.include? attr }
49
+ end
50
+
51
+ if attrs.empty?
52
+ confidence = CONFIDENCE[:med]
53
+ else
54
+ confidence = CONFIDENCE[:high]
55
+ end
56
+
57
+ warn :model => model[:name],
58
+ :warning_type => "Remote Code Execution",
59
+ :message => "Serialized attributes are vulnerable in Rails #{tracker.config[:rails_version]}, upgrade to #{@upgrade_version} or patch.",
60
+ :confidence => confidence,
61
+ :link => "https://groups.google.com/d/topic/rubyonrails-security/KtmwSbEpzrU/discussion"
62
+ end
63
+ end
64
+ end
@@ -8,7 +8,7 @@ class Brakeman::CheckSend < Brakeman::BaseCheck
8
8
 
9
9
  def run_check
10
10
  Brakeman.debug("Finding instances of #send")
11
- calls = tracker.find_call :method => :send
11
+ calls = tracker.find_call :methods => [:send, :try, :__send__, :public_send]
12
12
 
13
13
  calls.each do |call|
14
14
  process_result call
@@ -17,7 +17,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
17
17
  @rails_version = tracker.config[:rails_version]
18
18
 
19
19
  @sql_targets = [:all, :average, :calculate, :count, :count_by_sql, :exists?,
20
- :find, :find_by_sql, :first, :last, :maximum, :minimum, :sum]
20
+ :find, :find_by_sql, :first, :last, :maximum, :minimum, :pluck, :sum, :update_all]
21
21
 
22
22
  if tracker.options[:rails3]
23
23
  @sql_targets.concat [:from, :group, :having, :joins, :lock, :order, :reorder, :select, :where]
@@ -138,9 +138,15 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
138
138
  end
139
139
 
140
140
  def check_rails_version_for_cve_2013_0155
141
- if version_between?("2.0.0", "2.3.15") || version_between?("3.0.0", "3.0.18") || version_between?("3.1.0", "3.1.9") || version_between?("3.2.0", "3.2.10")
141
+ if version_between?("3.0.0", "3.0.18") || version_between?("3.1.0", "3.1.9") || version_between?("3.2.0", "3.2.10")
142
+ message = 'All versions of Rails before 3.0.19, 3.1.10, and 3.2.11 contain a SQL Injection Vulnerability: CVE-2013-0155; Upgrade to 3.2.11, 3.1.10, 3.0.19'
143
+ elsif version_between?("2.0.0", "2.3.15")
144
+ message = "Rails #{@rails_version} contains a SQL Injection Vulnerability: CVE-2013-0155; Upgrade to 2.3.16"
145
+ end
146
+
147
+ if message
142
148
  warn :warning_type => 'SQL Injection',
143
- :message => 'All versions of Rails before 3.0.19, 3.1.10, and 3.2.11 contain a SQL Injection Vulnerability: CVE-2013-0155; Upgrade to 3.2.11, 3.1.10, 3.0.19',
149
+ :message => message,
144
150
  :confidence => CONFIDENCE[:high],
145
151
  :file => gemfile_or_environment,
146
152
  :link_path => "https://groups.google.com/d/topic/rubyonrails-security/c7jT-EeN9eI/discussion"
@@ -229,6 +235,10 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
229
235
  unsafe_sql? call.first_arg
230
236
  when :lock
231
237
  check_lock_arguments call.first_arg
238
+ when :pluck
239
+ unsafe_sql? call.first_arg
240
+ when :update_all
241
+ check_update_all_arguments call.args
232
242
  else
233
243
  Brakeman.debug "Unhandled SQL method: #{method}"
234
244
  end
@@ -372,6 +382,15 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
372
382
  end
373
383
  end
374
384
 
385
+ def check_update_all_arguments args
386
+ args.each do |arg|
387
+ res = unsafe_sql? arg
388
+ return res if res
389
+ end
390
+
391
+ nil
392
+ end
393
+
375
394
  #Model#lock essentially only cares about strings. But those strings can be
376
395
  #any SQL fragment. This does not apply to all databases. (For those who do not
377
396
  #support it, the lock method does nothing).
@@ -7,7 +7,9 @@ class Brakeman::CheckYAMLLoad < Brakeman::BaseCheck
7
7
  @description = "Checks for uses of YAML.load"
8
8
 
9
9
  def run_check
10
- tracker.find_call(:target => :YAML, :method => :load).each do |result|
10
+ yaml_methods = [:load, :load_documents, :load_stream, :parse_documents, :parse_stream]
11
+
12
+ tracker.find_call(:target => :YAML, :methods => yaml_methods ).each do |result|
11
13
  check_yaml_load result
12
14
  end
13
15
  end
@@ -17,6 +19,7 @@ class Brakeman::CheckYAMLLoad < Brakeman::BaseCheck
17
19
  add_result result
18
20
 
19
21
  arg = result[:call].first_arg
22
+ method = result[:call].method
20
23
 
21
24
  if input = has_immediate_user_input?(arg)
22
25
  confidence = CONFIDENCE[:high]
@@ -38,7 +41,7 @@ class Brakeman::CheckYAMLLoad < Brakeman::BaseCheck
38
41
  "user input"
39
42
  end
40
43
 
41
- message = "YAML.load called with #{input_type}"
44
+ message = "YAML.#{method} called with #{input_type}"
42
45
 
43
46
  warn :result => result,
44
47
  :warning_type => "Remote Code Execution",
@@ -38,6 +38,7 @@ class Brakeman::CheckYAMLParsing < Brakeman::BaseCheck
38
38
  warn :warning_type => "Remote Code Execution",
39
39
  :message => message,
40
40
  :confidence => CONFIDENCE[:high],
41
+ :file => gemfile_or_environment,
41
42
  :link_path => "https://groups.google.com/d/topic/rubyonrails-security/61bkgvnSGTQ/discussion"
42
43
  end
43
44
  end
@@ -14,6 +14,7 @@ class Brakeman::GemProcessor < Brakeman::BaseProcessor
14
14
 
15
15
  if gem_lock
16
16
  get_rails_version gem_lock
17
+ get_json_version gem_lock
17
18
  elsif @tracker.config[:gems][:rails] =~ /(\d+.\d+.\d+)/
18
19
  @tracker.config[:rails_version] = $1
19
20
  end
@@ -40,9 +41,18 @@ class Brakeman::GemProcessor < Brakeman::BaseProcessor
40
41
  exp
41
42
  end
42
43
 
44
+ #Need to implement generic gem version check
45
+ def get_version name, gem_lock
46
+ match = gem_lock.match(/\s#{name} \((\d+.\d+.\d+.*)\)$/)
47
+ match[1] if match
48
+ end
49
+
43
50
  def get_rails_version gem_lock
44
- if gem_lock =~ /\srails \((\d+.\d+.\d+.*)\)$/
45
- @tracker.config[:rails_version] = $1
46
- end
51
+ @tracker.config[:rails_version] = get_version("rails", gem_lock)
52
+ end
53
+
54
+ def get_json_version gem_lock
55
+ @tracker.config[:gems][:json] = get_version("json", gem_lock)
56
+ @tracker.config[:gems][:json_pure] = get_version("json_pure", gem_lock)
47
57
  end
48
58
  end
@@ -13,7 +13,7 @@ module Brakeman::RenderHelper
13
13
  when :default
14
14
  begin
15
15
  process_template template_name, exp[3]
16
- rescue ArgumentError => e
16
+ rescue ArgumentError
17
17
  Brakeman.debug "Problem processing render: #{exp}"
18
18
  end
19
19
  when :partial, :layout
@@ -18,8 +18,26 @@ else
18
18
  # CSV is now FasterCSV in ruby 1.9
19
19
  end
20
20
 
21
+ #MultiJson interface changed in 1.3.0, but need
22
+ #to support older MultiJson for Rails 3.1.
23
+ if MultiJson.respond_to? :default_adapter
24
+ mj_engine = MultiJson.default_adapter
25
+ else
26
+ mj_engine = MultiJson.default_engine
27
+
28
+ module MultiJson
29
+ def self.dump *args
30
+ encode *args
31
+ end
32
+
33
+ def self.load *args
34
+ decode *args
35
+ end
36
+ end
37
+ end
38
+
21
39
  #This is so OkJson will work with symbol values
22
- if MultiJson.default_adapter == :ok_json
40
+ if mj_engine == :ok_json
23
41
  class Symbol
24
42
  def to_json
25
43
  self.to_s.inspect
@@ -694,11 +712,13 @@ HEADER
694
712
  :brakeman_version => Brakeman::Version
695
713
  }
696
714
 
697
- MultiJson.dump({
715
+ report_info = {
698
716
  :scan_info => scan_info,
699
717
  :warnings => warnings,
700
718
  :errors => errors
701
- }, :pretty => true)
719
+ }
720
+
721
+ MultiJson.dump(report_info, :pretty => true)
702
722
  end
703
723
 
704
724
  def all_warnings
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "1.9.1"
2
+ Version = "1.9.2"
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman
3
3
  version: !ruby/object:Gem::Version
4
- hash: 49
4
+ hash: 55
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 9
9
- - 1
10
- version: 1.9.1
9
+ - 2
10
+ version: 1.9.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Justin Collins
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-01-19 00:00:00 Z
18
+ date: 2013-02-14 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: ruby_parser
@@ -146,11 +146,11 @@ dependencies:
146
146
  requirements:
147
147
  - - ~>
148
148
  - !ruby/object:Gem::Version
149
- hash: 9
149
+ hash: 11
150
150
  segments:
151
151
  - 1
152
- - 3
153
- version: "1.3"
152
+ - 2
153
+ version: "1.2"
154
154
  type: :runtime
155
155
  version_requirements: *id009
156
156
  description: Brakeman detects security vulnerabilities in Ruby on Rails applications via static analysis.
@@ -181,6 +181,7 @@ files:
181
181
  - lib/brakeman/checks/check_select_vulnerability.rb
182
182
  - lib/brakeman/checks/check_escape_function.rb
183
183
  - lib/brakeman/checks/check_single_quotes.rb
184
+ - lib/brakeman/checks/check_model_serialize.rb
184
185
  - lib/brakeman/checks/check_basic_auth.rb
185
186
  - lib/brakeman/checks/check_safe_buffer_manipulation.rb
186
187
  - lib/brakeman/checks/check_forgery_setting.rb
@@ -204,6 +205,7 @@ files:
204
205
  - lib/brakeman/checks/check_digest_dos.rb
205
206
  - lib/brakeman/checks/check_render.rb
206
207
  - lib/brakeman/checks/check_send_file.rb
208
+ - lib/brakeman/checks/check_json_parsing.rb
207
209
  - lib/brakeman/checks/check_execute.rb
208
210
  - lib/brakeman/checks/check_translate_bug.rb
209
211
  - lib/brakeman/checks/check_default_routes.rb