Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [day] [month] [year] [list]
Date: Tue, 18 Feb 2014 11:04:47 -0800
From: Aaron Patterson <tenderlove@...y-lang.org>
To: rubyonrails-security@...glegroups.com, oss-security@...ts.openwall.com,
	secalert@...hat.com
Subject: Data Injection Vulnerability in Active Record (CVE-2014-0080)

Data Injection Vulnerability in Active Record

There is a data injection vulnerability in Active Record. Specially
crafted strings can be used to save data in PostgreSQL array columns that may
not be intended. This vulnerability has been assigned the CVE identifier
CVE-2014-0080.

Versions Affected:  4.0.x, 4.1.0.beta1
Not affected:       3.2.x and older
Fixed Versions:     4.0.3, 4.1.0.beta2

Impact
------
Specially crafted strings may be used to save data to array columns in
PostgreSQL databases. This vulnerability cannot be used to delete data or
execute arbitrary SQL statements, but *can* be used to add data that could
have an impact on the application (such as setting an admin flag). Only array
type columns in PostgreSQL are impacted.

All users running an affected release should either upgrade or use one of the
work arounds immediately.

Releases
--------
The FIXED releases are available at the normal locations.

Workarounds
-----------
To work around this issue, apply this monkey patch:

```ruby
module ActiveRecord
  module ConnectionAdapters
    class PostgreSQLColumn
      module Cast
        alias :old_quote_and_escape :quote_and_escape

        ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
        def quote_and_escape(value)
          case value
          when "NULL", Numeric
            value
          else
            value = value.gsub(/\\/, ARRAY_ESCAPE)
            value.gsub!(/"/,"\\\"")
            "\"#{value}\""
          end
        end
      end
    end
  end
end
```

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.

* 4-1-beta-array_injection.patch - Patch for 4.1-beta series
* 4-0-array_injection.patch - Patch for 4.0 series

Credits
-------

Thanks Godfrey Chan for reporting this!

-- 
Aaron Patterson
http://tenderlovemaking.com/

From 3eaea655a506ed035fab3d143aa918958cf52405 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@...il.com>
Date: Wed, 12 Feb 2014 16:22:40 -0800
Subject: [PATCH] Correctly escape PostgreSQL arrays.

Thanks Godfrey Chan for reporting this!

Fixes: CVE-2014-0080
---
 .../lib/active_record/connection_adapters/postgresql/cast.rb      | 6 +++++-
 activerecord/test/cases/adapters/postgresql/datatype_test.rb      | 8 ++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index a73f0ac..eac828b 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -138,12 +138,16 @@ module ActiveRecord
             end
           end
 
+          ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
+
           def quote_and_escape(value)
             case value
             when "NULL"
               value
             else
-              "\"#{value.gsub(/"/,"\\\"")}\""
+              value = value.gsub(/\\/, ARRAY_ESCAPE)
+              value.gsub!(/"/,"\\\"")
+              "\"#{value}\""
             end
           end
       end
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index 1b2f5f0..6c78a51 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -184,6 +184,14 @@ _SQL
     assert_equal :text, @first_array.column_for_attribute(:nicknames).type
   end
 
+  def test_array_escaping
+    unknown = %(foo\\",bar,baz,\\)
+    nicknames = ["hello_#{unknown}"]
+    ar = PostgresqlArray.create!(nicknames: nicknames, id: 100)
+    ar.reload
+    assert_equal nicknames, ar.nicknames
+  end
+
   def test_data_type_of_range_types
     skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
     assert_equal :daterange, @first_range.column_for_attribute(:date_range).type
-- 
1.8.4.3


From 6256b1de9a2d968b0d123ad6a09b33de01019ae6 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@...il.com>
Date: Wed, 12 Feb 2014 16:22:40 -0800
Subject: [PATCH] Correctly escape PostgreSQL arrays.

Thanks Godfrey Chan for reporting this!

Fixes: CVE-2014-0080
---
 .../lib/active_record/connection_adapters/postgresql/cast.rb      | 6 +++++-
 activerecord/test/cases/adapters/postgresql/datatype_test.rb      | 8 ++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index bf34f2b..bb6ea95 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -142,12 +142,16 @@ module ActiveRecord
             end
           end
 
+          ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
+
           def quote_and_escape(value)
             case value
             when "NULL"
               value
             else
-              "\"#{value.gsub(/"/,"\\\"")}\""
+              value = value.gsub(/\\/, ARRAY_ESCAPE)
+              value.gsub!(/"/,"\\\"")
+              "\"#{value}\""
             end
           end
 
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index 04a458f..5c3a797 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -78,6 +78,14 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
      PostgresqlBitString, PostgresqlOid, PostgresqlTimestampWithZone, PostgresqlUUID].each(&:delete_all)
   end
 
+  def test_array_escaping
+    unknown = %(foo\\",bar,baz,\\)
+    nicknames = ["hello_#{unknown}"]
+    ar = PostgresqlArray.create!(nicknames: nicknames, id: 100)
+    ar.reload
+    assert_equal nicknames, ar.nicknames
+  end
+
   def test_data_type_of_array_types
     assert_equal :integer, @first_array.column_for_attribute(:commission_by_quarter).type
     assert_equal :text, @first_array.column_for_attribute(:nicknames).type
-- 
1.8.4.3



[ CONTENT OF TYPE application/pgp-signature SKIPPED ]

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Powered by Openwall GNU/*/Linux - Powered by OpenVZ