Fwd: [oss-security] SQL Injection Vulnerability in Ruby on Rails
(CVE-2012-2661)
Eitan Adler
lists at eitanadler.com
Sat Jun 2 05:57:47 UTC 2012
A vulnerability has been found in a port you maintain. Please commit
an update and write up a VuXML report. If you need help feel free to
email ports-security at freebsd.org,
---------- Forwarded message ----------
From: Aaron Patterson <tenderlove at ruby-lang.org>
Date: 31 May 2012 15:16
Subject: [oss-security] SQL Injection Vulnerability in Ruby on Rails
(CVE-2012-2661)
To: oss-security at lists.openwall.com
SQL Injection Vulnerability in Ruby on Rails
There is a SQL injection vulnerability in Active Record, version 3.0
and later. This vulnerability has been assigned the CVE identifier
CVE-2012-2661.
Versions Affected: 3.0.0 and ALL later versions
Not affected: 2.3.14
Fixed Versions: 3.2.4, 3.1.5, 3.0.13
Impact
------
Due to the way Active Record handles nested query parameters, an
attacker can use a specially crafted request to inject some forms of
SQL into your application's SQL queries.
All users running an affected release should upgrade immediately.
Impacted code directly passes request params to the `where` method of
an ActiveRecord class like this:
Post.where(:id => params[:id]).all
An attacker can make a request that causes `params[:id]` to return a
specially crafted hash that will cause the WHERE clause of the SQL
statement to query an arbitrary table with some value.
Releases
--------
The FIXED releases are available at the normal locations.
Workarounds
-----------
This issue can be mitigated by casting the parameter to an expected
value. For example, change this:
Post.where(:id => params[:id]).all
to this:
Post.where(:id => params[:id].to_s).all
Patches
-------
To aid users who aren't able to upgrade immediately we have provided
patches for the two supported release series. They are in git-am
format and consist of a single changeset. We have also provided a
patch for the 3.0 series despite the fact it is unmaintained.
* 3-0-params_sql_injection.patch - Patch for 3.0 series
* 3-1-params_sql_injection.patch - Patch for 3.1 series
* 3-2-params_sql_injection.patch - Patch for 3.2 series
Please note that only the 3.1.x and 3.2.x series are supported at
present. Users of earlier unsupported releases are advised to upgrade
as soon as possible as we cannot guarantee the continued availability
of security fixes for unsupported releases.
Credits
-------
Thanks to Ben Murphy for reporting the vulnerability to us, and to
Chad Pyne of thoughtbot for helping us verify the fix.
--
Aaron Patterson
http://tenderlovemaking.com/
--
Eitan Adler
-------------- next part --------------
From 99f030934eb8341db333cb6783d0f42bfa57358f Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson at gmail.com>
Date: Wed, 30 May 2012 15:06:12 -0700
Subject: [PATCH] predicate builder should not recurse for determining where
columns. Thanks to Ben Murphy for reporting this
CVE-2012-2661
---
.../active_record/relation/predicate_builder.rb | 6 +++---
activerecord/test/cases/relation/where_test.rb | 19 +++++++++++++++++++
2 files changed, 22 insertions(+), 3 deletions(-)
create mode 100644 activerecord/test/cases/relation/where_test.rb
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 505c3f4..84e88cf 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -5,17 +5,17 @@ module ActiveRecord
@engine = engine
end
- def build_from_hash(attributes, default_table)
+ def build_from_hash(attributes, default_table, check_column = true)
predicates = attributes.map do |column, value|
table = default_table
if value.is_a?(Hash)
table = Arel::Table.new(column, :engine => @engine)
- build_from_hash(value, table)
+ build_from_hash(value, table, false)
else
column = column.to_s
- if column.include?('.')
+ if check_column && column.include?('.')
table_name, column = column.split('.', 2)
table = Arel::Table.new(table_name, :engine => @engine)
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
new file mode 100644
index 0000000..90c690e
--- /dev/null
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -0,0 +1,19 @@
+require "cases/helper"
+require 'models/post'
+
+module ActiveRecord
+ class WhereTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def test_where_error
+ assert_raises(ActiveRecord::StatementInvalid) do
+ Post.where(:id => { 'posts.author_id' => 10 }).first
+ end
+ end
+
+ def test_where_with_table_name
+ post = Post.first
+ assert_equal post, Post.where(:posts => { 'id' => post.id }).first
+ end
+ end
+end
--
1.7.5.4
-------------- next part --------------
From b71d4ab9d7d61ebe3411a8754e9fe93d3587704e Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson at gmail.com>
Date: Wed, 30 May 2012 15:05:19 -0700
Subject: [PATCH] predicate builder should not recurse for determining where
columns. Thanks to Ben Murphy for reporting this
CVE-2012-2661
---
.../associations/association_scope.rb | 17 ++++++++++++++++-
.../active_record/relation/predicate_builder.rb | 6 +++---
activerecord/test/cases/relation/where_test.rb | 19 +++++++++++++++++++
3 files changed, 38 insertions(+), 4 deletions(-)
create mode 100644 activerecord/test/cases/relation/where_test.rb
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 6cc401e..8e1df35 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -87,7 +87,7 @@ module ActiveRecord
conditions.each do |condition|
if options[:through] && condition.is_a?(Hash)
- condition = { table.name => condition }
+ condition = disambiguate_condition(table, condition)
end
scope = scope.where(interpolate(condition))
@@ -126,6 +126,21 @@ module ActiveRecord
end
end
+ def disambiguate_condition(table, condition)
+ if condition.is_a?(Hash)
+ Hash[
+ condition.map do |k, v|
+ if v.is_a?(Hash)
+ [k, v]
+ else
+ [table.table_alias || table.name, { k => v }]
+ end
+ end
+ ]
+ else
+ condition
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 7e8ddd1..0e436e8 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -1,16 +1,16 @@
module ActiveRecord
class PredicateBuilder # :nodoc:
- def self.build_from_hash(engine, attributes, default_table)
+ def self.build_from_hash(engine, attributes, default_table, check_column = true)
predicates = attributes.map do |column, value|
table = default_table
if value.is_a?(Hash)
table = Arel::Table.new(column, engine)
- build_from_hash(engine, value, table)
+ build_from_hash(engine, value, table, false)
else
column = column.to_s
- if column.include?('.')
+ if check_column && column.include?('.')
table_name, column = column.split('.', 2)
table = Arel::Table.new(table_name, engine)
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
new file mode 100644
index 0000000..90c690e
--- /dev/null
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -0,0 +1,19 @@
+require "cases/helper"
+require 'models/post'
+
+module ActiveRecord
+ class WhereTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def test_where_error
+ assert_raises(ActiveRecord::StatementInvalid) do
+ Post.where(:id => { 'posts.author_id' => 10 }).first
+ end
+ end
+
+ def test_where_with_table_name
+ post = Post.first
+ assert_equal post, Post.where(:posts => { 'id' => post.id }).first
+ end
+ end
+end
--
1.7.5.4
-------------- next part --------------
From 71f7917c553cdc9a0ee49e87af0efb7429759718 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson at gmail.com>
Date: Wed, 30 May 2012 15:04:11 -0700
Subject: [PATCH] predicate builder should not recurse for determining where
columns. Thanks to Ben Murphy for reporting this
CVE-2012-2661
---
.../associations/association_scope.rb | 17 ++++++++++++++++-
.../active_record/relation/predicate_builder.rb | 6 +++---
activerecord/test/cases/relation/where_test.rb | 19 +++++++++++++++++++
3 files changed, 38 insertions(+), 4 deletions(-)
create mode 100644 activerecord/test/cases/relation/where_test.rb
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index b3819e3..f9cffa4 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -75,7 +75,7 @@ module ActiveRecord
conditions.each do |condition|
if options[:through] && condition.is_a?(Hash)
- condition = { table.name => condition }
+ condition = disambiguate_condition(table, condition)
end
scope = scope.where(interpolate(condition))
@@ -114,6 +114,21 @@ module ActiveRecord
end
end
+ def disambiguate_condition(table, condition)
+ if condition.is_a?(Hash)
+ Hash[
+ condition.map do |k, v|
+ if v.is_a?(Hash)
+ [k, v]
+ else
+ [table.table_alias || table.name, { k => v }]
+ end
+ end
+ ]
+ else
+ condition
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index a789f48..9c84d8a 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -1,16 +1,16 @@
module ActiveRecord
class PredicateBuilder # :nodoc:
- def self.build_from_hash(engine, attributes, default_table)
+ def self.build_from_hash(engine, attributes, default_table, check_column = true)
predicates = attributes.map do |column, value|
table = default_table
if value.is_a?(Hash)
table = Arel::Table.new(column, engine)
- build_from_hash(engine, value, table)
+ build_from_hash(engine, value, table, false)
else
column = column.to_s
- if column.include?('.')
+ if check_column && column.include?('.')
table_name, column = column.split('.', 2)
table = Arel::Table.new(table_name, engine)
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
new file mode 100644
index 0000000..90c690e
--- /dev/null
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -0,0 +1,19 @@
+require "cases/helper"
+require 'models/post'
+
+module ActiveRecord
+ class WhereTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def test_where_error
+ assert_raises(ActiveRecord::StatementInvalid) do
+ Post.where(:id => { 'posts.author_id' => 10 }).first
+ end
+ end
+
+ def test_where_with_table_name
+ post = Post.first
+ assert_equal post, Post.where(:posts => { 'id' => post.id }).first
+ end
+ end
+end
--
1.7.5.4
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 497 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-ruby/attachments/20120602/64d0c88a/attachment.pgp
More information about the freebsd-ruby
mailing list