[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

ActiveMQ security update



Hello security team,

I have prepared a security update for ActiveMQ regarding CVE-2015-5254.
Please find attached the proposed debdiff for Jessie.

Unfortunately this patch relies on classes in libxstream-java that are
not present in Wheezy. We could backport the Jessie version of
libxstream-java to Wheezy but before I need to do some tests with its
reverse-dependencies.

Regards,

Markus
diff -Nru activemq-5.6.0+dfsg1/debian/changelog activemq-5.6.0+dfsg1/debian/changelog
--- activemq-5.6.0+dfsg1/debian/changelog	2015-08-03 21:30:49.000000000 +0200
+++ activemq-5.6.0+dfsg1/debian/changelog	2016-03-16 21:20:06.000000000 +0100
@@ -1,3 +1,14 @@
+activemq (5.6.0+dfsg1-4+deb8u2) jessie-security; urgency=high
+
+  * Team upload.
+  * Fix CVE-2015-5254:
+    Apache ActiveMQ 5.x before 5.13.0 does not restrict the classes that can be
+    serialized in the broker, which allows remote attackers to execute
+    arbitrary code via a crafted serialized Java Message Service (JMS)
+    ObjectMessage object.
+
+ -- Markus Koschany <apo@debian.org>  Wed, 16 Mar 2016 19:30:17 +0100
+
 activemq (5.6.0+dfsg1-4+deb8u1) jessie-security; urgency=high
 
   * Team upload.
diff -Nru activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch
--- activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch	1970-01-01 01:00:00.000000000 +0100
+++ activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch	2016-03-16 21:20:06.000000000 +0100
@@ -0,0 +1,253 @@
+From: Markus Koschany <apo@debian.org>
+Date: Wed, 16 Mar 2016 19:26:46 +0100
+Subject: CVE-2015-5254
+
+Apache ActiveMQ 5.x before 5.13.0 does not restrict the classes that can be
+serialized in the broker, which allows remote attackers to execute arbitrary
+code via a crafted serialized Java Message Service (JMS) ObjectMessage object.
+
+Origin: https://git-wip-us.apache.org/repos/asf?p=activemq.git;h=6f03921b31d9fefeddb0f4fa63150ed1f94a14b1
+Origin: https://git-wip-us.apache.org/repos/asf?p=activemq.git;h=73a0caf758f9e4916783a205c7e422b4db27905c
+Origin: http://pkgs.fedoraproject.org/cgit/activemq.git/diff/activemq-5.6.0-CVE-2015-5254.patch?id=e3ef8a1b62d10273a814090be9168aa3019ace72
+Debian-Bug: https://bugs.debian.org/809733
+---
+ .../transport/stomp/JmsFrameTranslator.java        |  5 ++-
+ .../activemq/transport/stomp/XStreamSupport.java   | 47 +++++++++++++++++++++
+ .../util/ClassLoadingAwareObjectInputStream.java   | 48 ++++++++++++++++++++--
+ .../transport/xstream/XStreamWireFormat.java       | 29 ++++++++++++-
+ .../java/org/apache/activemq/web/MessageQuery.java |  4 +-
+ 5 files changed, 124 insertions(+), 9 deletions(-)
+ create mode 100644 activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java
+
+diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java
+index 5274b34..4fd18b0 100644
+--- a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java
++++ b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java
+@@ -84,7 +84,7 @@ public class JmsFrameTranslator extends LegacyFrameTranslator implements
+                     msg = createMapMessage(in);
+                     break;
+                 default:
+-                    throw new Exception("Unkown transformation: " + transformation);
++                    throw new Exception("Unknown transformation: " + transformation);
+                 }
+             } catch (Throwable e) {
+                 command.getHeaders().put(Stomp.Headers.TRANSFORMATION_ERROR, e.getMessage());
+@@ -243,7 +243,8 @@ public class JmsFrameTranslator extends LegacyFrameTranslator implements
+         }
+ 
+         if (xstream == null) {
+-            xstream = new XStream();
++            xstream = XStreamSupport.createXStream();
++            xstream.ignoreUnknownElements();
+         }
+         return xstream;
+ 
+diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java
+new file mode 100644
+index 0000000..abcca72
+--- /dev/null
++++ b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java
+@@ -0,0 +1,47 @@
++/**
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++package org.apache.activemq.transport.stomp;
++
++import com.thoughtworks.xstream.XStream;
++import com.thoughtworks.xstream.security.AnyTypePermission;
++import com.thoughtworks.xstream.security.NoTypePermission;
++import com.thoughtworks.xstream.security.PrimitiveTypePermission;
++import org.apache.activemq.util.ClassLoadingAwareObjectInputStream;
++
++import java.util.Collection;
++import java.util.Map;
++
++public class XStreamSupport {
++
++    public static XStream createXStream() {
++        XStream stream = new XStream();
++        stream.addPermission(NoTypePermission.NONE);
++        stream.addPermission(PrimitiveTypePermission.PRIMITIVES);
++        stream.allowTypeHierarchy(Collection.class);
++        stream.allowTypeHierarchy(Map.class);
++        stream.allowTypes(new Class[]{String.class});
++        if (ClassLoadingAwareObjectInputStream.isAllAllowed()) {
++            stream.addPermission(AnyTypePermission.ANY);
++        } else {
++            for (String packageName : ClassLoadingAwareObjectInputStream.serializablePackages) {
++                stream.allowTypesByWildcard(new String[]{packageName + ".**"});
++            }
++        }
++        return stream;
++    }
++
++}
+diff --git a/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java b/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java
+index 82da30c..6a2864f 100644
+--- a/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java
++++ b/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java
+@@ -21,7 +21,10 @@ import java.io.InputStream;
+ import java.io.ObjectInputStream;
+ import java.io.ObjectStreamClass;
+ import java.lang.reflect.Proxy;
++import java.util.Arrays;
++import java.util.Collection;
+ import java.util.HashMap;
++import java.util.Map;
+ 
+ @SuppressWarnings("rawtypes")
+ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
+@@ -29,6 +32,12 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
+     private static final ClassLoader FALLBACK_CLASS_LOADER =
+         ClassLoadingAwareObjectInputStream.class.getClassLoader();
+ 
++    public static final String[] serializablePackages;
++
++    static {
++        serializablePackages = System.getProperty("org.apache.activemq.SERIALIZABLE_PACKAGES", "java.lang,java.util,org.apache.activemq,org.fusesource.hawtbuf,com.thoughtworks.xstream.mapper").split(",");
++    }
++
+     /**
+      * Maps primitive type names to corresponding class objects.
+      */
+@@ -40,7 +49,9 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
+ 
+     protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
+         ClassLoader cl = Thread.currentThread().getContextClassLoader();
+-        return load(classDesc.getName(), cl);
++        Class clazz = load(classDesc.getName(), cl);
++        checkSecurity(clazz);
++        return clazz;
+     }
+ 
+     protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
+@@ -50,18 +61,47 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
+             cinterfaces[i] = load(interfaces[i], cl);
+         }
+ 
++        Class clazz = null;
+         try {
+-            return Proxy.getProxyClass(cl, cinterfaces);
++            clazz = Proxy.getProxyClass(cl, cinterfaces);
+         } catch (IllegalArgumentException e) {
+             try {
+-                return Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
++                clazz = Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
+             } catch (IllegalArgumentException e1) {
+             }
+ 
+-            throw new ClassNotFoundException(null, e);
++        }
++
++        if (clazz != null) {
++            checkSecurity(clazz);
++            return clazz;
++        } else {
++            throw new ClassNotFoundException(null);
+         }
+     }
+ 
++    public static boolean isAllAllowed() {
++        return serializablePackages.length == 1 && serializablePackages[0].equals("*");
++    }
++
++    private void checkSecurity(Class clazz) throws ClassNotFoundException {
++        if (!clazz.isPrimitive()) {
++            if (clazz.getPackage() != null && !isAllAllowed()) {
++               boolean found = false;
++               for (String packageName : serializablePackages) {
++                   if (clazz.getPackage().getName().equals(packageName) || clazz.getPackage().getName().startsWith(packageName + ".")) {
++                       found = true;
++                       break;
++                   }
++               }
++
++               if (!found) {
++                   throw new ClassNotFoundException("Forbidden " + clazz + "! This class is not allowed to be serialized. Add package with 'org.apache.activemq.SERIALIZABLE_PACKAGES' system property.");
++               }
++            }
++         }
++     }
++
+     private Class<?> load(String className, ClassLoader cl) throws ClassNotFoundException {
+         try {
+             return Class.forName(className, false, cl);
+diff --git a/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java b/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java
+index 91ae036..1b83e2e 100755
+--- a/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java
++++ b/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java
+@@ -17,9 +17,15 @@
+ package org.apache.activemq.transport.xstream;
+ 
+ import com.thoughtworks.xstream.XStream;
++import com.thoughtworks.xstream.converters.Converter;
++import com.thoughtworks.xstream.converters.MarshallingContext;
++import com.thoughtworks.xstream.converters.UnmarshallingContext;
++import com.thoughtworks.xstream.io.HierarchicalStreamReader;
++import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+ import org.apache.activemq.command.Command;
+ import org.apache.activemq.command.MarshallAware;
+ import org.apache.activemq.command.MessageDispatch;
++import org.apache.activemq.transport.stomp.XStreamSupport;
+ import org.apache.activemq.transport.util.TextWireFormat;
+ import org.apache.activemq.wireformat.WireFormat;
+ 
+@@ -105,7 +111,28 @@ public class XStreamWireFormat extends TextWireFormat {
+     // Implementation methods
+     // -------------------------------------------------------------------------
+     protected XStream createXStream() {
+-        return new XStream();
++        final XStream xstream = XStreamSupport.createXStream();
++        xstream.ignoreUnknownElements();
++        xstream.registerConverter(new Converter() {
++            final Converter delegate = xstream.getConverterLookup().lookupConverterForType(ByteSequence.class);
++            @Override
++            public void marshal(Object o, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) {
++                ByteSequence byteSequence = (ByteSequence)o;
++                byteSequence.compact();
++                delegate.marshal(byteSequence, hierarchicalStreamWriter, marshallingContext);
++            }
++
++            @Override
++            public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) {
++                return delegate.unmarshal(hierarchicalStreamReader, unmarshallingContext);
++            }
++
++            @Override
++            public boolean canConvert(Class aClass) {
++                return aClass == ByteSequence.class;
++            }
++        });
++        return xstream;
+     }
+ 
+ }
+diff --git a/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java b/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java
+index 1d0ec06..a6cbd51 100644
+--- a/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java
++++ b/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java
+@@ -80,9 +80,9 @@ public class MessageQuery extends QueueBrowseQuery {
+         if (message instanceof ObjectMessage) {
+             try {
+                 return ((ObjectMessage) message).getObject();
+-            } catch (JMSException e) {
++            } catch (Exception e) {
+                 //message could not be parsed, make the reason available
+-                return e;
++                return new String("Cannot display ObjectMessage body. Reason: " + e.getMessage());
+             }
+         }
+         if (message instanceof MapMessage) {
diff -Nru activemq-5.6.0+dfsg1/debian/patches/series activemq-5.6.0+dfsg1/debian/patches/series
--- activemq-5.6.0+dfsg1/debian/patches/series	2015-08-03 15:08:47.000000000 +0200
+++ activemq-5.6.0+dfsg1/debian/patches/series	2016-03-16 21:20:06.000000000 +0100
@@ -10,3 +10,4 @@
 CVE-2014-3600.patch
 CVE-2014-3612.patch
 CVE-2014-3576.patch
+CVE-2015-5254.patch

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: