2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
RMI (Remote Method Invocation) is a basic idea in distributed programming. There are many technologies for implementing remote method invocation, such as CORBA and WebService, both of which are independent of each programming language. Java RMI is a remote method invocation mechanism designed specifically for the Java environment. It is a Java API for implementing remote procedures (RPC), which can directly transmit serialized Java objects and distributed garbage collection. Its implementation depends on the JVM, so it supports calls from one JVM to another. In Java RMI, the remote server implements specific Java methods and provides interfaces. The local client only needs to provide corresponding parameters according to the definition of the interface class to call the remote method, where the object is encoded and transmitted in a serialized manner. So the exploitation of deserialization vulnerabilities often involves RMI, which is what it means. The communication protocol that RMI relies on is JRMP (Java Remote Message Protocol), which is customized for Java and requires that both the server and the client must be written in Java.
The interaction process can be simply summarized as:
Experiment with a simple rmi service and call it through the client
This is a server-side project, mainly providing rmi service interface
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>rmi</artifactId>
- <groupId>com.et</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>rmi-server</artifactId>
-
- <properties>
- <maven.compiler.source>8</maven.compiler.source>
- <maven.compiler.target>8</maven.compiler.target>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-autoconfigure</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
- <dependency>
- <groupId>com.et</groupId>
- <artifactId>rmi-common</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>com.h2database</groupId>
- <artifactId>h2</artifactId>
- <version>1.4.200</version>
- </dependency>
- </dependencies>
- </project>
- package com.et.rmi.server.config;
-
- import com.et.rmi.server.dao.CustomerRepository;
-
- import com.et.rmi.server.model.Customer;
- import com.et.rmi.server.service.CustomerServiceImpl;
- import om.et.rmi.common.CustomerService;
- import org.springframework.boot.ApplicationArguments;
- import org.springframework.boot.ApplicationRunner;
- import org.springframework.context.annotation.Bean;
- import org.springframework.remoting.rmi.RmiServiceExporter;
- import org.springframework.stereotype.Component;
-
- import java.util.logging.Logger;
-
- @Component
- public class RmiServerApplicationRunner implements ApplicationRunner {
-
- private CustomerRepository repository;
- private CustomerServiceImpl customerService;
- private final Logger log = Logger.getLogger(this.getClass().getName());
-
- public RmiServerApplicationRunner(CustomerServiceImpl customerService) {
- this.customerService = customerService;
- }
-
- @Override
- public void run(ApplicationArguments args) throws Exception {
- Customer customer1 = new Customer("John", "Smith", "123-456-7890");
- customerService.saveCustomer(customer1);
- customerService.getCustomers().forEach(System.out::println);
- }
-
- @Bean
- public RmiServiceExporter customerServiceExporter() {
- RmiServiceExporter customerServiceExporter = new RmiServiceExporter();
- customerServiceExporter.setRegistryPort(1199);
- customerServiceExporter.setServiceName("customerService");
- customerServiceExporter.setServiceInterface(CustomerService.class);
- customerServiceExporter.setService(customerService);
- log.info("Started RMI Server");
- return customerServiceExporter;
- }
- }
- package com.et.rmi.server.service;
-
- import com.et.rmi.server.dao.CustomerRepository;
-
- import com.et.rmi.server.mapper.CustomerMapper;
- import com.et.rmi.server.model.Customer;
- import om.et.rmi.common.CustomerDTO;
- import om.et.rmi.common.CustomerService;
- import org.springframework.stereotype.Service;
-
- import java.util.List;
-
- @Service
- public class CustomerServiceImpl implements CustomerService {
-
- private CustomerRepository repository;
-
- public CustomerServiceImpl(CustomerRepository repository) {
- this.repository = repository;
- }
-
- @Override
- public CustomerDTO getCustomer(long id) {
- Customer customer = repository.findById(id).orElseThrow(IllegalArgumentException::new);
- CustomerMapper mapper = new CustomerMapper();
- CustomerDTO dto = mapper.mapToDTO(customer);
- System.out.println(dto);
- return dto;
- }
-
- public List<Customer> getCustomers() {
- return (List<Customer>)repository.findAll();
- }
- public void saveCustomer(Customer customer) {
- repository.save(customer);
- }
- }
- package com.et.rmi.server.dao;
-
- import com.et.rmi.server.model.Customer;
- import org.springframework.data.repository.CrudRepository;
- import org.springframework.stereotype.Repository;
-
- import java.util.Optional;
-
- @Repository
- public interface CustomerRepository extends CrudRepository<Customer, Long> {
- Optional<Customer> findById(long id);
- }
- package com.et.rmi.server.mapper;
-
- import com.et.rmi.server.model.Customer;
-
- import om.et.rmi.common.CustomerDTO;
-
- public class CustomerMapper {
-
- public CustomerMapper() {
- }
-
- public CustomerDTO mapToDTO(Customer customer){
- CustomerDTO dto = new CustomerDTO();
- dto.setFirstName(customer.getFirstName());
- dto.setLastName(customer.getLastName());
- dto.setSocialSecurityCode(customer.getSocialSecurityCode());
- return dto;
- }
- }
- package com.et.rmi.server.model;
-
-
- import javax.persistence.*;
-
- @Entity
- @SequenceGenerator(name = "CUST_SEQ", initialValue = 1_000_001)
- public class Customer {
-
- @Id
- @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUST_SEQ")
- private long id;
- private String firstName;
- private String lastName;
- private String socialSecurityCode;
-
- public Customer() {
- }
-
- public Customer(String firstName, String lastName, String socialSecurityCode) {
- this.firstName = firstName;
- this.lastName = lastName;
- this.socialSecurityCode = socialSecurityCode;
- }
-
- public long getId() {
- return id;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- public String getSocialSecurityCode() {
- return socialSecurityCode;
- }
-
- public void setSocialSecurityCode(String socialSecurityCode) {
- this.socialSecurityCode = socialSecurityCode;
- }
-
- @Override
- public String toString() {
- return "Customer{" +
- "id=" + id +
- ", firstName='" + firstName + ''' +
- ", lastName='" + lastName + ''' +
- ", socialSecurityCode='" + socialSecurityCode + ''' +
- '}';
- }
- }
spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
This is a client project, mainly calling the remote rmi service
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>rmi</artifactId>
- <groupId>com.et</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>rmi-cilent</artifactId>
-
- <properties>
- <maven.compiler.source>8</maven.compiler.source>
- <maven.compiler.target>8</maven.compiler.target>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-autoconfigure</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.et</groupId>
- <artifactId>rmi-common</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- </dependencies>
- </project>
- package com.et.rmi.client.controller;
-
-
- import om.et.rmi.common.CustomerDTO;
- import om.et.rmi.common.CustomerService;
- import org.springframework.http.MediaType;
- import org.springframework.http.ResponseEntity;
- import org.springframework.remoting.rmi.RmiProxyFactoryBean;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
-
- @Controller
- @RequestMapping(value = "customers")
- public class CustomerController {
-
- private RmiProxyFactoryBean proxyFactoryBean;
-
- public CustomerController(RmiProxyFactoryBean proxyFactoryBean) {
- this.proxyFactoryBean = proxyFactoryBean;
- }
-
- @RequestMapping(value = "{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity<CustomerDTO> getCustomer(@PathVariable long id) {
- CustomerService service = (CustomerService) proxyFactoryBean.getObject();
- CustomerDTO dto = service.getCustomer(id);
- return ResponseEntity.ok(dto);
- }
- }
- package com.et.rmi.client.config;
-
- import om.et.rmi.common.CustomerService;
- import org.springframework.context.annotation.Bean;
- import org.springframework.remoting.rmi.RmiProxyFactoryBean;
- import org.springframework.stereotype.Component;
- import org.springframework.util.StringUtils;
-
- import java.util.logging.Logger;
-
- @Component
- public class Config {
-
- public final Logger log = Logger.getLogger(this.getClass().getName());
-
- @Bean
- public RmiProxyFactoryBean proxyFactoryBean() {
- String remoteHost = System.getProperty("RMI_SERVER_HOST");
- if(StringUtils.isEmpty(remoteHost)){
- remoteHost="127.0.0.1";
- }
- String rmiHost = String.format("rmi://%s:1199/customerService", remoteHost);
- log.info("RMI Host name is " + rmiHost);
- RmiProxyFactoryBean proxy = new RmiProxyFactoryBean();
- proxy.setServiceInterface(CustomerService.class);
- proxy.setServiceUrl(rmiHost);
- proxy.afterPropertiesSet();
- return proxy;
- }
- }
server.port=8081
This is a public package, both server and client must reference it
- package om.et.rmi.common;
-
- import java.io.Serializable;
-
- public class CustomerDTO implements Serializable {
-
- private String firstName;
- private String lastName;
- private String socialSecurityCode;
-
- public CustomerDTO() {
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- public String getSocialSecurityCode() {
- return socialSecurityCode;
- }
-
- public void setSocialSecurityCode(String socialSecurityCode) {
- this.socialSecurityCode = socialSecurityCode;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("CustomerDTO{");
- sb.append("firstName='").append(firstName).append(''');
- sb.append(", lastName='").append(lastName).append(''');
- sb.append(", socialSecurityCode='").append(socialSecurityCode).append(''');
- sb.append('}');
- return sb.toString();
- }
- }
- package om.et.rmi.common;
-
- public interface CustomerService {
- CustomerDTO getCustomer(long id);
- }
The above are just some key codes. For all codes, please refer to the following code repository
{"firstName":"John","lastName":"Smith","socialSecurityCode":"123-456-7890"}