水洞之Apache Jackrabbit-CVE-2023-37895
漏洞概述
Apache Jackrabbit是一个强大的开源内容存储库,实现了Java的内容存储库规范(JSR-170和JSR-283)。Apache Jackrabbit webapp/standalone多个版本中存在Java 对象反序列化漏洞,由于使用的commons-beanutils 组件中存在一个可通过 RMI 远程执行代码的类,可通过构造恶意序列化数据,并发送到目标系统上的 RMI 服务端口(默认为1099端口)或发送到RMI-over-HTTP路径(默认使用路径“/rmi”),当目标系统反序列化该数据时可能导致远程代码执行。
漏洞分析
在漏洞概述中说到,在路径/rmi中,会引起RMI远程代码执行,通过web.xml找到/rmi
路由对应的Servlet
<servlet>
<servlet-name>RMI</servlet-name>
<servlet-class>org.apache.jackrabbit.servlet.remote.RemoteBindingServlet</servlet-class>
</servlet>
对应的类为org.apache.jackrabbit.servlet.remote.RemoteBindingServlet
,只有doGet方法
protected void doGet(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/octet-stream");
ObjectOutputStream output =
new ObjectOutputStream(response.getOutputStream());
output.writeObject(RemoteObject.toStub(getRemoteRepository()));
output.flush();
}
先调用getRemoteRepository
获取Repository
protected RemoteRepository getRemoteRepository() throws ServletException {
if (remote == null) {
try {
RemoteAdapterFactory factory = getRemoteAdapterFactory();
remote = factory.getRemoteRepository(new ServletRepository(this));
} catch (RemoteException e) {
throw new ServletException(
"Failed to create the remote repository reference", e);
}
}
return remote;
}
在获取Repository的同时,调用了getRemoteAdapterFactory
去获取Factory,然后调用Factory的getRemoteRepository
方法,会返回一个ServerRepository
对象
public ServerRepository(
Repository repository, RemoteAdapterFactory factory)
throws RemoteException {
super(factory);
this.repository = repository;
}
然后返回给客户端这个远程获取到的类
客户端拿到这个Repository后,可以调用其中的login
方法
此时的remote是RemoteRepository
类,也是就会调用服务端的login
方法
ClientRepository
的login
当中存在一个Credentials
,实现了Serializable接口
Credentials
接口的实现类之一SimpleCredentials
存在一个attributes
属性,是一个HashMap
该项目自带commons-beanutils1.9.4,我们可以用cb链来打。
Exp
把cb链生成的PriorityQueue
类作为Attribute属性封装成SimpleCredentials
,在反序列化的时候,会先反序列化SimpleCredentials里的Attribute,也就是HashMap,然后反序列化HashMap中的PriorityQueue
,即可触发RCE。