[Into the pit JAVA security] RMI basics read this article is enough

0x01 basic concepts

The full name of RMI is Remote Method Invocation, that is, remote method invocation, how to implement it? The remote server provides specific classes and methods. The local will obtain a proxy of the remote class in some way , and then call the method of the remote object through this proxy. The parameters of the method are passed through serialization and deserialization, so, 1. As long as the server object provides a method, this method receives an Object type parameter, 2. And there is an available pop chain in the classpath of the remote server, then we can call this method on the client and pass it A carefully constructed object approach to attack rmi services.

0x02 implementation mechanism

As mentioned above, the local will obtain the proxy of the remote object in some way, so what is the specific implementation mechanism? In addition to Client and Server in RMI mode, a Registry is also used.

Server Registry Client
Provide specific remote objects A registry that stores the location of remote objects (ip, port, identifier) User of remote object

Among them, Server and Registry can be implemented on the same server or deployed on different servers. Now a complete RMI process can be roughly described as:

  1. Registry first starts and listens on a port, generally 1099
  2. Server registers remote objects with Registry
  3. The Client obtains the proxy of the remote object from the Registry (this proxy knows the specific location of the remote object in the network: ip, port, identifier), and then the Client calls the remote method through this proxy. The Server also has a proxy, and the proxy on the Server side will After receiving the method and parameters called by the Client, the agent executes the corresponding method and returns the result to the Client via the network.

Two pictures are worth a thousand words:

The overall process:

Insert picture description here
ps: The stub in the picture is the client proxy, and the skeleton is the server proxy. I really can’t understand the English name given by a foreigner~

Communication mode of remote method call:

Insert picture description here

I wonder if anyone like me has thought about why this registration form is needed?

0x03 code implementation

We already know the general process, so how to implement the above process with code? Let's create a project by ourselves. The project structure is as follows:

Insert picture description here

1. First create an interface Hello:

package model;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
    
    
    public String welcome(String name) throws RemoteException;
}

2. Implement a class Helloimpl based on this interface:

package model.impl;

import model.Hello;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class Helloimpl extends UnicastRemoteObject implements Hello {
    
    
    public Helloimpl() throws RemoteException {
    
    
    }

    @Override
    public String welcome(String name) throws RemoteException {
    
    
        return "Hello, "+name;
    }
}

3. Create the server, the server creates a registry and registers the objects needed by the client

package server;

import model.Hello;
import model.impl.Helloimpl;
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{
    
    
        // 创建对象
        Hello hello = new Helloimpl();
        // 创建注册表
        Registry registry = LocateRegistry.createRegistry(1099);
        // 绑定对象到注册表,并给他取名为hello
        registry.rebind("hello", hello);
    }
}

4. The client calls the remote object

package client;
import model.Hello;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {
    
    
    public static void main(String[] args) throws RemoteException, NotBoundException {
    
    
        // 获取到注册表的代理
        Registry registry = LocateRegistry.getRegistry("localhost", 1099);
        // 利用注册表的代理去查询远程注册表中名为hello的对象
        Hello hello = (Hello) registry.lookup("hello");
        // 调用远程方法
        System.out.println(hello.welcome("axin"));
    }
}

Start the server first. After starting the client, the client successfully executes the remote method and obtains the returned data:

Insert picture description here

There are a few things to note when writing code:

  1. The interface needs to integrate the Remote interface, and the method needs to throw a RemoteException error
  2. The implementation class of the interface needs to inherit UnicastRemoteObject, and the same method needs to throw RemoteException error
  3. If the remote method needs to pass parameters, you need to ensure that the parameters are serializable. I just pass the string here. The string is serializable. If the passed parameter is a custom object, then the object needs to implement the Serilizable interface

Note that since the server and client are implemented on the same machine here, it seems relatively simple. If the server and the client are not on the same host, you need to ensure that the interface implemented by the called remote object is on the client Both exist on the server side!

0x04 other

It’s almost done here, for the time being to meet our need to learn about rmi deserialization vulnerabilities. If you are curious about the implementation of the underlying code of rmi, you can read the source code of jdk again, which will deepen your understanding of rmi~

Put an article that analyzes the implementation of rmi from the source level: https://xz.aliyun.com/t/2223

While reading the article, it is best to combine practice

Follow my official account and play together

Insert picture description here

Guess you like

Origin blog.csdn.net/he_and/article/details/105532007