Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [day] [month] [year] [list]
Date: Mon, 18 Mar 2013 10:22:15 -0700
From: Aaron Patterson <tenderlove@...y-lang.org>
To: rubyonrails-security@...glegroups.com, oss-security@...ts.openwall.com,
	ruby-security-ann@...glegroups.com
Subject: [CVE-2013-1856] XML Parsing Vulnerability affecting JRuby users

XML Parsing Vulnerability affecting JRuby users

There is a vulnerability in the JDOM backend to ActiveSupport's XML parser.  This could allow an attacker to perform a denial of service attack or gain access to files stored on the application server.  This vulnerability has been assigned the CVE identifier CVE-2013-1856.

Versions Affected:  3.0.0 and All Later Versions when using JRuby
Not affected:       Applications not using JRuby or JRuby applications not using the JDOM backend.	
Fixed Versions:     3.2.13, 3.1.12

Impact 
------ 
The ActiveSupport XML parsing functionality supports multiple pluggable backends.  One backend supported for JRuby users is ActiveSupport::XmlMini_JDOM which makes use of the javax.xml.parsers.DocumentBuilder class.

In some JVM configurations the default settings of that class can allow an attacker to construct XML which, when parsed, will contain the contents of arbitrary URLs including files from the application server.  They may also allow for various denial of service attacks.

If you are using JRuby and have an affected JVM, you should upgrade or use one of the work arounds immediately.

Releases 
-------- 
The 3.2.13 and 3.1.12 releases are available at the normal locations. 

Workarounds 
----------- 
If you are unable to upgrade, you can place this code in an application initializer to prevent this issue:

  ActiveSupport::XmlMini.backend="REXML"

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. 

* 3-2-jdom.patch - Patch for 3.2 series 
* 3-1-jdom.patch - Patch for 3.1 series 
* 3-0-jdom.patch - Patch for 3.0 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 this vulnerability to us and working with us to inform other affected libraries and programming languages.

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

From 6d930adfeaae6cbed22d1e97ccd401bbc61407ab Mon Sep 17 00:00:00 2001
From: Ben Murphy <benmmurphy@...il.com>
Date: Fri, 8 Feb 2013 02:48:22 +0000
Subject: [PATCH] JDOM XXE Protection

Conflicts:
	activesupport/test/xml_mini/jdom_engine_test.rb

Conflicts:
	activesupport/test/xml_mini/jdom_engine_test.rb
---
 activesupport/lib/active_support/xml_mini/jdom.rb |  6 ++++
 activesupport/test/fixtures/xml/jdom_doctype.dtd  |  1 +
 activesupport/test/fixtures/xml/jdom_entities.txt |  1 +
 activesupport/test/fixtures/xml/jdom_include.txt  |  1 +
 activesupport/test/xml_mini/jdom_engine_test.rb   | 40 ++++++++++++++++++++---
 5 files changed, 45 insertions(+), 4 deletions(-)
 create mode 100644 activesupport/test/fixtures/xml/jdom_doctype.dtd
 create mode 100644 activesupport/test/fixtures/xml/jdom_entities.txt
 create mode 100644 activesupport/test/fixtures/xml/jdom_include.txt

diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
index 102b9be..0e3522f 100644
--- a/activesupport/lib/active_support/xml_mini/jdom.rb
+++ b/activesupport/lib/active_support/xml_mini/jdom.rb
@@ -38,6 +38,12 @@ module ActiveSupport
         {}
       else
         @dbf = DocumentBuilderFactory.new_instance
+        # secure processing of java xml
+        # http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html
+        @dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
+        @dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
+        @dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
+        @dbf.setFeature(javax.xml.XMLConstants::FEATURE_SECURE_PROCESSING, true)
         xml_string_reader = StringReader.new(data)
         xml_input_source = InputSource.new(xml_string_reader)
         doc = @dbf.new_document_builder.parse(xml_input_source)
diff --git a/activesupport/test/fixtures/xml/jdom_doctype.dtd b/activesupport/test/fixtures/xml/jdom_doctype.dtd
new file mode 100644
index 0000000..8948049
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_doctype.dtd
@@ -0,0 +1 @@
+<!ENTITY a "external entity">
diff --git a/activesupport/test/fixtures/xml/jdom_entities.txt b/activesupport/test/fixtures/xml/jdom_entities.txt
new file mode 100644
index 0000000..0337fda
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_entities.txt
@@ -0,0 +1 @@
+<!ENTITY a "hello">
diff --git a/activesupport/test/fixtures/xml/jdom_include.txt b/activesupport/test/fixtures/xml/jdom_include.txt
new file mode 100644
index 0000000..239ca3a
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_include.txt
@@ -0,0 +1 @@
+include me
diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb
index ae35dbc..9a4661e 100644
--- a/activesupport/test/xml_mini/jdom_engine_test.rb
+++ b/activesupport/test/xml_mini/jdom_engine_test.rb
@@ -3,10 +3,11 @@ if RUBY_PLATFORM =~ /java/
   require 'active_support/xml_mini'
   require 'active_support/core_ext/hash/conversions'
 
-
-  class JDOMEngineTest < Test::Unit::TestCase
+  class JDOMEngineTest < ActiveSupport::TestCase
     include ActiveSupport
 
+    FILES_DIR = File.dirname(__FILE__) + '/../fixtures/xml'
+
     def setup
       @default_backend = XmlMini.backend
       XmlMini.backend  = 'JDOM'
@@ -31,10 +32,41 @@ if RUBY_PLATFORM =~ /java/
        assert_equal 'image/png', file.content_type
     end
 
+    def test_not_allowed_to_expand_entities_to_files
+      attack_xml = <<-EOT
+      <!DOCTYPE member [
+        <!ENTITY a SYSTEM "file://#{FILES_DIR}/jdom_include.txt">
+      ]>
+      <member>x&a;</member>
+      EOT
+      assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+    end
+
+  def test_not_allowed_to_expand_parameter_entities_to_files
+      attack_xml = <<-EOT
+      <!DOCTYPE member [
+        <!ENTITY % b SYSTEM "file://#{FILES_DIR}/jdom_entities.txt">
+        %b;
+      ]>
+      <member>x&a;</member>
+      EOT
+      assert_raise Java::OrgXmlSax::SAXParseException do
+        assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+      end
+    end
+
+
+    def test_not_allowed_to_load_external_doctypes
+      attack_xml = <<-EOT
+      <!DOCTYPE member SYSTEM "file://#{FILES_DIR}/jdom_doctype.dtd">
+      <member>x&a;</member>
+      EOT
+      assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+    end
+
     def test_exception_thrown_on_expansion_attack
-      assert_raise NativeException do
+      assert_raise Java::OrgXmlSax::SAXParseException do
         attack_xml = <<-EOT
-      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE member [
         <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
         <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
-- 
1.8.1.1


From 6a3ca3601258e2c1a41a4297855c008f6ab87b44 Mon Sep 17 00:00:00 2001
From: Ben Murphy <benmmurphy@...il.com>
Date: Fri, 8 Feb 2013 02:48:22 +0000
Subject: [PATCH] JDOM XXE Protection

Conflicts:
	activesupport/test/xml_mini/jdom_engine_test.rb
---
 activesupport/lib/active_support/xml_mini/jdom.rb |  6 ++++
 activesupport/test/fixtures/xml/jdom_doctype.dtd  |  1 +
 activesupport/test/fixtures/xml/jdom_entities.txt |  1 +
 activesupport/test/fixtures/xml/jdom_include.txt  |  1 +
 activesupport/test/xml_mini/jdom_engine_test.rb   | 39 +++++++++++++++++++++--
 5 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 activesupport/test/fixtures/xml/jdom_doctype.dtd
 create mode 100644 activesupport/test/fixtures/xml/jdom_entities.txt
 create mode 100644 activesupport/test/fixtures/xml/jdom_include.txt

diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
index 6c222b8..8d23ce4 100644
--- a/activesupport/lib/active_support/xml_mini/jdom.rb
+++ b/activesupport/lib/active_support/xml_mini/jdom.rb
@@ -38,6 +38,12 @@ module ActiveSupport
         {}
       else
         @dbf = DocumentBuilderFactory.new_instance
+        # secure processing of java xml
+        # http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html
+        @dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
+        @dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
+        @dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
+        @dbf.setFeature(javax.xml.XMLConstants::FEATURE_SECURE_PROCESSING, true)
         xml_string_reader = StringReader.new(data)
         xml_input_source = InputSource.new(xml_string_reader)
         doc = @dbf.new_document_builder.parse(xml_input_source)
diff --git a/activesupport/test/fixtures/xml/jdom_doctype.dtd b/activesupport/test/fixtures/xml/jdom_doctype.dtd
new file mode 100644
index 0000000..8948049
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_doctype.dtd
@@ -0,0 +1 @@
+<!ENTITY a "external entity">
diff --git a/activesupport/test/fixtures/xml/jdom_entities.txt b/activesupport/test/fixtures/xml/jdom_entities.txt
new file mode 100644
index 0000000..0337fda
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_entities.txt
@@ -0,0 +1 @@
+<!ENTITY a "hello">
diff --git a/activesupport/test/fixtures/xml/jdom_include.txt b/activesupport/test/fixtures/xml/jdom_include.txt
new file mode 100644
index 0000000..239ca3a
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_include.txt
@@ -0,0 +1 @@
+include me
diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb
index 7f809e7..ec81ada 100644
--- a/activesupport/test/xml_mini/jdom_engine_test.rb
+++ b/activesupport/test/xml_mini/jdom_engine_test.rb
@@ -3,9 +3,11 @@ if RUBY_PLATFORM =~ /java/
   require 'active_support/xml_mini'
   require 'active_support/core_ext/hash/conversions'
 
-  class JDOMEngineTest < Test::Unit::TestCase
+  class JDOMEngineTest < ActiveSupport::TestCase
     include ActiveSupport
 
+    FILES_DIR = File.dirname(__FILE__) + '/../fixtures/xml'
+
     def setup
       @default_backend = XmlMini.backend
       XmlMini.backend = 'JDOM'
@@ -30,10 +32,41 @@ if RUBY_PLATFORM =~ /java/
        assert_equal 'image/png', file.content_type
     end
 
+    def test_not_allowed_to_expand_entities_to_files
+      attack_xml = <<-EOT
+      <!DOCTYPE member [
+        <!ENTITY a SYSTEM "file://#{FILES_DIR}/jdom_include.txt">
+      ]>
+      <member>x&a;</member>
+      EOT
+      assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+    end
+
+  def test_not_allowed_to_expand_parameter_entities_to_files
+      attack_xml = <<-EOT
+      <!DOCTYPE member [
+        <!ENTITY % b SYSTEM "file://#{FILES_DIR}/jdom_entities.txt">
+        %b;
+      ]>
+      <member>x&a;</member>
+      EOT
+      assert_raise Java::OrgXmlSax::SAXParseException do
+        assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+      end
+    end
+
+
+    def test_not_allowed_to_load_external_doctypes
+      attack_xml = <<-EOT
+      <!DOCTYPE member SYSTEM "file://#{FILES_DIR}/jdom_doctype.dtd">
+      <member>x&a;</member>
+      EOT
+      assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+    end
+
     def test_exception_thrown_on_expansion_attack
-      assert_raise NativeException do
+      assert_raise Java::OrgXmlSax::SAXParseException do
         attack_xml = <<-EOT
-      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE member [
         <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
         <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
-- 
1.8.1.1


From ccb5d375b8ca65a34bfad29227f02170564d1d83 Mon Sep 17 00:00:00 2001
From: Ben Murphy <benmmurphy@...il.com>
Date: Fri, 8 Feb 2013 02:48:22 +0000
Subject: [PATCH] JDOM XXE Protection

Conflicts:
	activesupport/test/xml_mini/jdom_engine_test.rb
---
 activesupport/lib/active_support/xml_mini/jdom.rb |  6 ++++
 activesupport/test/fixtures/xml/jdom_doctype.dtd  |  1 +
 activesupport/test/fixtures/xml/jdom_entities.txt |  1 +
 activesupport/test/fixtures/xml/jdom_include.txt  |  1 +
 activesupport/test/xml_mini/jdom_engine_test.rb   | 39 +++++++++++++++++++++--
 5 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 activesupport/test/fixtures/xml/jdom_doctype.dtd
 create mode 100644 activesupport/test/fixtures/xml/jdom_entities.txt
 create mode 100644 activesupport/test/fixtures/xml/jdom_include.txt

diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
index 0dee0f3..45a315e 100644
--- a/activesupport/lib/active_support/xml_mini/jdom.rb
+++ b/activesupport/lib/active_support/xml_mini/jdom.rb
@@ -38,6 +38,12 @@ module ActiveSupport
         {}
       else
         @dbf = DocumentBuilderFactory.new_instance
+        # secure processing of java xml
+        # http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html
+        @dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
+        @dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
+        @dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
+        @dbf.setFeature(javax.xml.XMLConstants::FEATURE_SECURE_PROCESSING, true)
         xml_string_reader = StringReader.new(data)
         xml_input_source = InputSource.new(xml_string_reader)
         doc = @dbf.new_document_builder.parse(xml_input_source)
diff --git a/activesupport/test/fixtures/xml/jdom_doctype.dtd b/activesupport/test/fixtures/xml/jdom_doctype.dtd
new file mode 100644
index 0000000..8948049
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_doctype.dtd
@@ -0,0 +1 @@
+<!ENTITY a "external entity">
diff --git a/activesupport/test/fixtures/xml/jdom_entities.txt b/activesupport/test/fixtures/xml/jdom_entities.txt
new file mode 100644
index 0000000..0337fda
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_entities.txt
@@ -0,0 +1 @@
+<!ENTITY a "hello">
diff --git a/activesupport/test/fixtures/xml/jdom_include.txt b/activesupport/test/fixtures/xml/jdom_include.txt
new file mode 100644
index 0000000..239ca3a
--- /dev/null
+++ b/activesupport/test/fixtures/xml/jdom_include.txt
@@ -0,0 +1 @@
+include me
diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb
index 7f809e7..ec81ada 100644
--- a/activesupport/test/xml_mini/jdom_engine_test.rb
+++ b/activesupport/test/xml_mini/jdom_engine_test.rb
@@ -3,9 +3,11 @@ if RUBY_PLATFORM =~ /java/
   require 'active_support/xml_mini'
   require 'active_support/core_ext/hash/conversions'
 
-  class JDOMEngineTest < Test::Unit::TestCase
+  class JDOMEngineTest < ActiveSupport::TestCase
     include ActiveSupport
 
+    FILES_DIR = File.dirname(__FILE__) + '/../fixtures/xml'
+
     def setup
       @default_backend = XmlMini.backend
       XmlMini.backend = 'JDOM'
@@ -30,10 +32,41 @@ if RUBY_PLATFORM =~ /java/
        assert_equal 'image/png', file.content_type
     end
 
+    def test_not_allowed_to_expand_entities_to_files
+      attack_xml = <<-EOT
+      <!DOCTYPE member [
+        <!ENTITY a SYSTEM "file://#{FILES_DIR}/jdom_include.txt">
+      ]>
+      <member>x&a;</member>
+      EOT
+      assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+    end
+
+  def test_not_allowed_to_expand_parameter_entities_to_files
+      attack_xml = <<-EOT
+      <!DOCTYPE member [
+        <!ENTITY % b SYSTEM "file://#{FILES_DIR}/jdom_entities.txt">
+        %b;
+      ]>
+      <member>x&a;</member>
+      EOT
+      assert_raise Java::OrgXmlSax::SAXParseException do
+        assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+      end
+    end
+
+
+    def test_not_allowed_to_load_external_doctypes
+      attack_xml = <<-EOT
+      <!DOCTYPE member SYSTEM "file://#{FILES_DIR}/jdom_doctype.dtd">
+      <member>x&a;</member>
+      EOT
+      assert_equal 'x', Hash.from_xml(attack_xml)["member"]
+    end
+
     def test_exception_thrown_on_expansion_attack
-      assert_raise NativeException do
+      assert_raise Java::OrgXmlSax::SAXParseException do
         attack_xml = <<-EOT
-      <?xml version="1.0" encoding="UTF-8"?>
       <!DOCTYPE member [
         <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
         <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
-- 
1.8.1.1



[ 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