brakeman 1.9.0 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,15 @@
1
+ # 1.9.1
2
+
3
+ * Update to RubyParser 3.1.1 (neersighted)
4
+ * Remove ActiveSupport dependency (Neil Matatall)
5
+ * Do not warn on arrays passed to `link_to` (Neil Matatall)
6
+ * Warn on secret tokens
7
+ * Warn on more mass assignment methods
8
+ * Add check for CVE-2012-5664
9
+ * Add check for CVE-2013-0155
10
+ * Add check for CVE-2013-0156
11
+ * Add check for unsafe `YAML.load`
12
+
1
13
  # 1.9.0
2
14
 
3
15
  * Update to RubyParser 3
@@ -65,6 +65,10 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
65
65
  # Decided NOT warn on models. polymorphic_path is called it a model is
66
66
  # passed to link_to (which passes it to url_for)
67
67
 
68
+ elsif array? url_arg
69
+ # Just like models, polymorphic path/url is called if the argument is
70
+ # an array
71
+
68
72
  elsif hash? url_arg
69
73
 
70
74
  # url_for uses the key/values pretty carefully and I don't see a risk.
@@ -29,7 +29,13 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
29
29
  :update_attributes!,
30
30
  :create,
31
31
  :create!,
32
- :build]
32
+ :build,
33
+ :first_or_create,
34
+ :first_or_create!,
35
+ :first_or_initialize!,
36
+ :assign_attributes,
37
+ :update
38
+ ]
33
39
 
34
40
  Brakeman.debug "Processing possible mass assignment calls"
35
41
  calls.each do |result|
@@ -79,11 +85,16 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
79
85
  #Want to ignore calls to Model.new that have no arguments
80
86
  def check_call call
81
87
  process_call_args call
82
- first_arg = call.first_arg
83
88
 
84
- if first_arg.nil? #empty new()
89
+ if call.method == :update
90
+ arg = call.second_arg
91
+ else
92
+ arg = call.first_arg
93
+ end
94
+
95
+ if arg.nil? #empty new()
85
96
  false
86
- elsif hash? first_arg and not include_user_input? first_arg
97
+ elsif hash? arg and not include_user_input? arg
87
98
  false
88
99
  elsif all_literal_args? call
89
100
  false
@@ -26,14 +26,27 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
26
26
  if tracker.initializers["session_store.rb"]
27
27
  process tracker.initializers["session_store.rb"]
28
28
  end
29
+
30
+ if tracker.initializers["secret_token.rb"]
31
+ process tracker.initializers["secret_token.rb"]
32
+ end
29
33
  end
30
34
 
31
35
  #Looks for ActionController::Base.session = { ... }
32
36
  #in Rails 2.x apps
37
+ #
38
+ #and App::Application.config.secret_token =
39
+ #in Rails 3.x apps
33
40
  def process_attrasgn exp
34
41
  if not tracker.options[:rails3] and exp.target == @session_settings and exp.method == :session=
35
42
  check_for_issues exp.first_arg, "#{tracker.options[:app_path]}/config/initializers/session_store.rb"
36
43
  end
44
+
45
+ if tracker.options[:rails3] and settings_target?(exp.target) and
46
+ exp.method == :secret_token= and string? exp.first_arg
47
+
48
+ warn_about_secret_token exp, "#{tracker.options[:app_path]}/config/initializers/secret_token.rb"
49
+ end
37
50
 
38
51
  exp
39
52
  end
@@ -69,8 +82,8 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
69
82
  end
70
83
 
71
84
  if value = hash_access(settings, :secret)
72
- if string? value and value.value.length < 30
73
- warn_about_secret_length value, file
85
+ if string? value
86
+ warn_about_secret_token value, file
74
87
  end
75
88
  end
76
89
  end
@@ -101,9 +114,9 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
101
114
 
102
115
  end
103
116
 
104
- def warn_about_secret_length value, file
117
+ def warn_about_secret_token value, file
105
118
  warn :warning_type => "Session Setting",
106
- :message => "Session secret should be at least 30 characters long",
119
+ :message => "Session secret should not be included in version control",
107
120
  :confidence => CONFIDENCE[:high],
108
121
  :line => value.line,
109
122
  :file => file
@@ -46,6 +46,12 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
46
46
  Brakeman.debug "Checking version of Rails for CVE-2012-2695"
47
47
  check_rails_version_for_cve_2012_2695
48
48
 
49
+ Brakeman.debug "Checking version of Rails for CVE-2012-5664"
50
+ check_rails_version_for_cve_2012_5664
51
+
52
+ Brakeman.debug "Checking version of Rails for CVE-2013-0155"
53
+ check_rails_version_for_cve_2013_0155
54
+
49
55
  Brakeman.debug "Processing possible SQL calls"
50
56
  calls.each do |c|
51
57
  process_result c
@@ -121,6 +127,26 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
121
127
  end
122
128
  end
123
129
 
130
+ def check_rails_version_for_cve_2012_5664
131
+ if version_between?("2.0.0", "2.3.14") || version_between?("3.0.0", "3.0.17") || version_between?("3.1.0", "3.1.8") || version_between?("3.2.0", "3.2.9")
132
+ warn :warning_type => 'SQL Injection',
133
+ :message => 'All versions of Rails before 3.0.18, 3.1.9, and 3.2.10 contain a SQL Injection Vulnerability: CVE-2012-5664; Upgrade to 3.2.10, 3.1.9, 3.0.18',
134
+ :confidence => CONFIDENCE[:high],
135
+ :file => gemfile_or_environment,
136
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/DCNTNp_qjFM/discussion"
137
+ end
138
+ end
139
+
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")
142
+ 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',
144
+ :confidence => CONFIDENCE[:high],
145
+ :file => gemfile_or_environment,
146
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/c7jT-EeN9eI/discussion"
147
+ end
148
+ end
149
+
124
150
  def process_scope_with_block model_name, args
125
151
  scope_name = args[1][1]
126
152
  block = args[-1][-1]
@@ -0,0 +1,51 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #YAML.load can be used for remote code execution
4
+ class Brakeman::CheckYAMLLoad < Brakeman::BaseCheck
5
+ Brakeman::Checks.add self
6
+
7
+ @description = "Checks for uses of YAML.load"
8
+
9
+ def run_check
10
+ tracker.find_call(:target => :YAML, :method => :load).each do |result|
11
+ check_yaml_load result
12
+ end
13
+ end
14
+
15
+ def check_yaml_load result
16
+ return if duplicate? result
17
+ add_result result
18
+
19
+ arg = result[:call].first_arg
20
+
21
+ if input = has_immediate_user_input?(arg)
22
+ confidence = CONFIDENCE[:high]
23
+ elsif input = include_user_input?(arg)
24
+ confidence = CONFIDENCE[:med]
25
+ end
26
+
27
+ if confidence
28
+ input_type = case input.type
29
+ when :params
30
+ "parameter value"
31
+ when :cookies
32
+ "cookies value"
33
+ when :request
34
+ "request value"
35
+ when :model
36
+ "model attribute"
37
+ else
38
+ "user input"
39
+ end
40
+
41
+ message = "YAML.load called with #{input_type}"
42
+
43
+ warn :result => result,
44
+ :warning_type => "Remote Code Execution",
45
+ :message => message,
46
+ :user_input => input.match,
47
+ :confidence => confidence,
48
+ :link_path => "remote_code_execution_yaml_load"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,118 @@
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 #{tracker.config[: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
+ :message => message,
29
+ :confidence => CONFIDENCE[:high],
30
+ :file => gemfile_or_environment,
31
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/61bkgvnSGTQ/discussion"
32
+ end
33
+
34
+ #Warn if app accepts YAML
35
+ if version_between?("0.0.0", "2.3.14") and enabled_yaml_parser?
36
+ message = "Parsing YAML request parameters enables remote code execution: disable YAML parser"
37
+
38
+ warn :warning_type => "Remote Code Execution",
39
+ :message => message,
40
+ :confidence => CONFIDENCE[:high],
41
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/61bkgvnSGTQ/discussion"
42
+ end
43
+ end
44
+
45
+ def disabled_xml_parser?
46
+ if version_between? "0.0.0", "2.3.14"
47
+ #Look for ActionController::Base.param_parsers.delete(Mime::XML)
48
+ params_parser = s(:call,
49
+ s(:colon2, s(:const, :ActionController), :Base),
50
+ :param_parsers)
51
+
52
+ matches = tracker.check_initializers(params_parser, :delete)
53
+ else
54
+ #Look for ActionDispatch::ParamsParser::DEFAULT_PARSERS.delete(Mime::XML)
55
+ matches = tracker.check_initializers(:"ActionDispatch::ParamsParser::DEFAULT_PARSERS", :delete)
56
+ end
57
+
58
+ unless matches.empty?
59
+ mime_xml = s(:colon2, s(:const, :Mime), :XML)
60
+
61
+ matches.each do |result|
62
+ if result.call.first_arg == mime_xml
63
+ return true
64
+ end
65
+ end
66
+ end
67
+
68
+ false
69
+ end
70
+
71
+ #Look for ActionController::Base.param_parsers[Mime::YAML] = :yaml
72
+ #in Rails 2.x apps
73
+ def enabled_yaml_parser?
74
+ param_parsers = s(:call,
75
+ s(:colon2, s(:const, :ActionController), :Base),
76
+ :param_parsers)
77
+
78
+ matches = tracker.check_initializers(param_parsers, :[]=)
79
+
80
+ mime_yaml = s(:colon2, s(:const, :Mime), :YAML)
81
+
82
+ matches.each do |result|
83
+ if result.call.first_arg == mime_yaml and
84
+ symbol? result.call.second_arg and
85
+ result.call.second_arg.value == :yaml
86
+
87
+ return true
88
+ end
89
+ end
90
+
91
+ false
92
+ end
93
+
94
+ def disabled_xml_dangerous_types?
95
+ if version_between? "0.0.0", "2.3.14"
96
+ matches = tracker.check_initializers(:"ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING", :delete)
97
+ else
98
+ matches = tracker.check_initializers(:"ActiveSupport::XmlMini::PARSING", :delete)
99
+ end
100
+
101
+ symbols_off = false
102
+ yaml_off = false
103
+
104
+ matches.each do |result|
105
+ arg = result.call.first_arg
106
+
107
+ if string? arg
108
+ if arg.value == "yaml"
109
+ yaml_off = true
110
+ elsif arg.value == "symbol"
111
+ symbols_off = true
112
+ end
113
+ end
114
+ end
115
+
116
+ symbols_off and yaml_off
117
+ end
118
+ end
@@ -146,6 +146,8 @@ class Brakeman::FindCall < Brakeman::BaseProcessor
146
146
  else
147
147
  false
148
148
  end
149
+ when Sexp
150
+ search_terms == item
149
151
  when Enumerable
150
152
  if search_terms.empty?
151
153
  item == nil
@@ -1,5 +1,4 @@
1
1
  require 'set'
2
- require 'active_support/inflector'
3
2
 
4
3
  #This is a mixin containing utility methods.
5
4
  module Brakeman::Util
@@ -40,11 +39,12 @@ module Brakeman::Util
40
39
  downcase
41
40
  end
42
41
 
43
- #Use ActiveSupport::Inflector to pluralize a word.
42
+ # stupid simple, used to delegate to ActiveSupport
44
43
  def pluralize word
45
- ActiveSupport::Inflector.pluralize word
44
+ word + "s"
46
45
  end
47
46
 
47
+
48
48
  #Takes an Sexp like
49
49
  # (:hash, (:lit, :key), (:str, "value"))
50
50
  #and yields the key and value pairs to the given block.
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "1.9.0"
2
+ Version = "1.9.1"
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: 51
4
+ hash: 49
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 9
9
- - 0
10
- version: 1.9.0
9
+ - 1
10
+ version: 1.9.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Justin Collins
@@ -15,56 +15,28 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-12-25 00:00:00 Z
18
+ date: 2013-01-19 00:00:00 Z
19
19
  dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: activesupport
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
32
- type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: i18n
36
- prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
46
- type: :runtime
47
- version_requirements: *id002
48
20
  - !ruby/object:Gem::Dependency
49
21
  name: ruby_parser
50
22
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
52
24
  none: false
53
25
  requirements:
54
26
  - - ~>
55
27
  - !ruby/object:Gem::Version
56
- hash: 15
28
+ hash: 1
57
29
  segments:
58
30
  - 3
59
- - 0
60
- - 4
61
- version: 3.0.4
31
+ - 1
32
+ - 1
33
+ version: 3.1.1
62
34
  type: :runtime
63
- version_requirements: *id003
35
+ version_requirements: *id001
64
36
  - !ruby/object:Gem::Dependency
65
37
  name: ruby2ruby
66
38
  prerelease: false
67
- requirement: &id004 !ruby/object:Gem::Requirement
39
+ requirement: &id002 !ruby/object:Gem::Requirement
68
40
  none: false
69
41
  requirements:
70
42
  - - ~>
@@ -75,11 +47,11 @@ dependencies:
75
47
  - 0
76
48
  version: "2.0"
77
49
  type: :runtime
78
- version_requirements: *id004
50
+ version_requirements: *id002
79
51
  - !ruby/object:Gem::Dependency
80
52
  name: terminal-table
81
53
  prerelease: false
82
- requirement: &id005 !ruby/object:Gem::Requirement
54
+ requirement: &id003 !ruby/object:Gem::Requirement
83
55
  none: false
84
56
  requirements:
85
57
  - - ~>
@@ -90,11 +62,11 @@ dependencies:
90
62
  - 4
91
63
  version: "1.4"
92
64
  type: :runtime
93
- version_requirements: *id005
65
+ version_requirements: *id003
94
66
  - !ruby/object:Gem::Dependency
95
67
  name: fastercsv
96
68
  prerelease: false
97
- requirement: &id006 !ruby/object:Gem::Requirement
69
+ requirement: &id004 !ruby/object:Gem::Requirement
98
70
  none: false
99
71
  requirements:
100
72
  - - ~>
@@ -105,11 +77,11 @@ dependencies:
105
77
  - 5
106
78
  version: "1.5"
107
79
  type: :runtime
108
- version_requirements: *id006
80
+ version_requirements: *id004
109
81
  - !ruby/object:Gem::Dependency
110
82
  name: highline
111
83
  prerelease: false
112
- requirement: &id007 !ruby/object:Gem::Requirement
84
+ requirement: &id005 !ruby/object:Gem::Requirement
113
85
  none: false
114
86
  requirements:
115
87
  - - ~>
@@ -120,11 +92,11 @@ dependencies:
120
92
  - 6
121
93
  version: "1.6"
122
94
  type: :runtime
123
- version_requirements: *id007
95
+ version_requirements: *id005
124
96
  - !ruby/object:Gem::Dependency
125
97
  name: erubis
126
98
  prerelease: false
127
- requirement: &id008 !ruby/object:Gem::Requirement
99
+ requirement: &id006 !ruby/object:Gem::Requirement
128
100
  none: false
129
101
  requirements:
130
102
  - - ~>
@@ -135,11 +107,11 @@ dependencies:
135
107
  - 6
136
108
  version: "2.6"
137
109
  type: :runtime
138
- version_requirements: *id008
110
+ version_requirements: *id006
139
111
  - !ruby/object:Gem::Dependency
140
112
  name: haml
141
113
  prerelease: false
142
- requirement: &id009 !ruby/object:Gem::Requirement
114
+ requirement: &id007 !ruby/object:Gem::Requirement
143
115
  none: false
144
116
  requirements:
145
117
  - - ~>
@@ -150,11 +122,11 @@ dependencies:
150
122
  - 0
151
123
  version: "3.0"
152
124
  type: :runtime
153
- version_requirements: *id009
125
+ version_requirements: *id007
154
126
  - !ruby/object:Gem::Dependency
155
127
  name: sass
156
128
  prerelease: false
157
- requirement: &id010 !ruby/object:Gem::Requirement
129
+ requirement: &id008 !ruby/object:Gem::Requirement
158
130
  none: false
159
131
  requirements:
160
132
  - - ~>
@@ -165,11 +137,11 @@ dependencies:
165
137
  - 0
166
138
  version: "3.0"
167
139
  type: :runtime
168
- version_requirements: *id010
140
+ version_requirements: *id008
169
141
  - !ruby/object:Gem::Dependency
170
142
  name: multi_json
171
143
  prerelease: false
172
- requirement: &id011 !ruby/object:Gem::Requirement
144
+ requirement: &id009 !ruby/object:Gem::Requirement
173
145
  none: false
174
146
  requirements:
175
147
  - - ~>
@@ -180,7 +152,7 @@ dependencies:
180
152
  - 3
181
153
  version: "1.3"
182
154
  type: :runtime
183
- version_requirements: *id011
155
+ version_requirements: *id009
184
156
  description: Brakeman detects security vulnerabilities in Ruby on Rails applications via static analysis.
185
157
  email:
186
158
  executables:
@@ -215,6 +187,7 @@ files:
215
187
  - lib/brakeman/checks/check_session_settings.rb
216
188
  - lib/brakeman/checks/check_model_attributes.rb
217
189
  - lib/brakeman/checks/check_redirect.rb
190
+ - lib/brakeman/checks/check_yaml_parsing.rb
218
191
  - lib/brakeman/checks/check_skip_before_filter.rb
219
192
  - lib/brakeman/checks/check_response_splitting.rb
220
193
  - lib/brakeman/checks/check_mail_to.rb
@@ -234,6 +207,7 @@ files:
234
207
  - lib/brakeman/checks/check_execute.rb
235
208
  - lib/brakeman/checks/check_translate_bug.rb
236
209
  - lib/brakeman/checks/check_default_routes.rb
210
+ - lib/brakeman/checks/check_yaml_load.rb
237
211
  - lib/brakeman/checks/check_link_to.rb
238
212
  - lib/brakeman/checks/check_quote_table_name.rb
239
213
  - lib/brakeman/checks/check_send.rb