为了便于测试反序列化漏洞,这里采用RMI服务作为示例,演示如何攻击一个RMI后端服务,因为RMI的通讯方式就是对象序列化/反序列化。
    添加commons-collections依赖:

    1. <dependency>
    2. <groupId>commons-collections</groupId>
    3. <artifactId>commons-collections</artifactId>
    4. <version>3.2.1</version>
    5. </dependency>

    RMITestInterface.java

    1. import java.rmi.Remote;
    2. import java.rmi.RemoteException;
    3. public interface RMITestInterface extends Remote {
    4. String test() throws RemoteException;
    5. }

    RMITestImpl.java

    1. import java.rmi.RemoteException;
    2. import java.rmi.server.UnicastRemoteObject;
    3. public class RMITestImpl extends UnicastRemoteObject implements RMITestInterface {
    4. private static final long serialVersionUID = 1L;
    5. protected RMITestImpl() throws RemoteException {
    6. super();
    7. }
    8. public String test() throws RemoteException {
    9. return "Hello RMI~";
    10. }
    11. }

    RMI服务端:

    1. import java.rmi.Naming;
    2. import java.rmi.registry.LocateRegistry;
    3. public class RMIServerTest {
    4. // RMI服务器IP地址
    5. public static final String RMI_HOST = "127.0.0.1";
    6. // RMI服务端口
    7. public static final int RMI_PORT = 9527;
    8. // RMI服务名称
    9. public static final String RMI_NAME = "rmi://" + RMI_HOST + ":" + RMI_PORT + "/test";
    10. public static void main(String[] args) {
    11. try {
    12. // 注册RMI端口
    13. LocateRegistry.createRegistry(RMI_PORT);
    14. // 绑定Remote对象
    15. Naming.bind(RMI_NAME, new RMITestImpl());
    16. System.out.println("RMI服务启动成功,服务地址:" + RMI_NAME);
    17. } catch (Exception e) {
    18. e.printStackTrace();
    19. }
    20. }
    21. }

    程序运行结果:RMI服务启动成功,服务地址:rmi://127.0.0.1:9527/test
    RMI客户端:

    1. package com.anbai.sec.rmi;
    2. import java.rmi.Naming;
    3. public class RMIClientTest {
    4. public static void main(String[] args) {
    5. try {
    6. // 查找远程RMI服务
    7. RMITestInterface rt = (RMITestInterface) Naming.lookup("rmi://127.0.0.1:9527/test");
    8. // 调用远程接口RMITestInterface类的test方法
    9. String result = rt.test();
    10. // 输出RMI方法调用结果
    11. System.out.println(result);
    12. } catch (Exception e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. }

    程序运行结果:Hello RMI~
    2. 1. RMI服务 - 图1
    上述示例演示了一个业务逻辑绝对的简单且安全RMI服务的正常业务流程,但是漏洞并不是出现在业务本身,而是Java的RMI服务和反序列化机制。