commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Karsten Klein (JIRA)" <j...@apache.org>
Subject [jira] [Comment Edited] (COLLECTIONS-580) Arbitrary remote code execution with InvokerTransformer
Date Fri, 13 Nov 2015 12:21:11 GMT

    [ https://issues.apache.org/jira/browse/COLLECTIONS-580?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15003912#comment-15003912
] 

Karsten Klein edited comment on COLLECTIONS-580 at 11/13/15 12:20 PM:
----------------------------------------------------------------------

We (not having seen the attached patch before) have come up with the following solution:

{code}
    /**
     * Transforms the input to result by invoking a method on the input.
     * 
     * @param input  the input object to transform
     * @return the transformed result, null if null input
     */
    public Object transform(Object input) {
        if (input == null) {
            return null;
        }
        
        if (deserialized) {
            throw new IllegalStateException("Transformation on deserialized object not supported.
"
                    + "Using this function may indicate an attempted SECURITY BREACH.");
        }
        
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(iMethodName, iParamTypes);
            return method.invoke(input, iArgs);
                
        } catch (NoSuchMethodException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName +
"' on '" + input.getClass() + "' does not exist");
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName +
"' on '" + input.getClass() + "' cannot be accessed");
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName +
"' on '" + input.getClass() + "' threw an exception", ex);
        }
    }
    
    private transient boolean deserialized = false;

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
        in.defaultReadObject();
        deserialized = true;
    }
{code}

This approach is a little more 'compatible' and less invasive. It will only fail if transform
is invoked on a deserialized object. In particular it does not fail at deserialization time.
Only when the transform method is invoked. This may reduce the effects of the change.



was (Author: karsten.klein@gmail.com):
We (not having seen the attached patch before) have come up with the following solution:

{code}
    /**
     * Transforms the input to result by invoking a method on the input.
     * 
     * @param input  the input object to transform
     * @return the transformed result, null if null input
     */
    public Object transform(Object input) {
        if (input == null) {
            return null;
        }
        
        if (deserialized) {
            throw new IllegalStateException("Transformation on deserialized object not supported.
"
                    + "Using this function may indicate an attempted SECURITY BREACH.");
        }
        
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(iMethodName, iParamTypes);
            return method.invoke(input, iArgs);
                
        } catch (NoSuchMethodException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName +
"' on '" + input.getClass() + "' does not exist");
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName +
"' on '" + input.getClass() + "' cannot be accessed");
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName +
"' on '" + input.getClass() + "' threw an exception", ex);
        }
    }
    
    private transient boolean deserialized = false;

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
        in.defaultReadObject();
        deserialized = true;
    }
{code}

This approach is the most non-invasive and 'compatible' approach. It will only fail if transform
is invoked on a deserialized object. In particular it does not fail at deserialization time.
Only when the transform method is invoked. This may reduce the effects of the change.


> Arbitrary remote code execution with InvokerTransformer
> -------------------------------------------------------
>
>                 Key: COLLECTIONS-580
>                 URL: https://issues.apache.org/jira/browse/COLLECTIONS-580
>             Project: Commons Collections
>          Issue Type: Bug
>    Affects Versions: 3.0, 4.0
>            Reporter: Philippe Marschall
>         Attachments: COLLECTIONS-580.patch
>
>
> With {{InvokerTransformer}} serializable collections can be build that execute arbitrary
Java code. {{sun.reflect.annotation.AnnotationInvocationHandler#readObject}} invokes {{#entrySet}}
and {{#get}} on a deserialized collection. If you have an endpoint that accepts serialized
Java objects (JMX, RMI, remote EJB, ...) you can combine the two to create arbitrary remote
code execution vulnerability.
> I don't know of a good fix short of removing {{InvokerTransformer}} or making it not
Serializable. Both probably break existing applications.
> This is not my research, but has been discovered by other people.
> https://github.com/frohoff/ysoserial
> http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message