Java反序列化:CommonsBeanutils无CC依赖下的反序列化调试分析
基础知识
1. Apache Commons Beanutils
Apache Commons BeanUtils 是 Apache Commons 项目的一部分,它是一个用于简化 Java 对象的操作和属性访问的工具库。具体来说,它提供了一组用于操作 JavaBean 对象的工具和方法,使开发人员能够更容易地进行属性的复制、获取和设置等操作。
- 本次涉及的相关类:Beancomparator
public class BeanComparator implements Comparator, Serializable {
private String property;
private Comparator comparator;
public BeanComparator() {
this((String)null);
}
public BeanComparator(String property) {
this(property, ComparableComparator.getInstance());
}
public BeanComparator(String property, Comparator comparator) {
this.setProperty(property);
if (comparator != null) {
this.comparator = comparator;
} else {
this.comparator = ComparableComparator.getInstance();
}
}
public void setProperty(String property) {
this.property = property;
}
public String getProperty() {
return this.property;
}
public Comparator getComparator() {
return this.comparator;
}
public int compare(Object o1, Object o2) {
if (this.property == null) {
return this.comparator.compare(o1, o2);
} else {
try {
Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.comparator.compare(value1, value2);
} catch (IllegalAccessException var5) {
throw new RuntimeException("IllegalAccessException: " + var5.toString());
} catch (InvocationTargetException var6) {
throw new RuntimeException("InvocationTargetException: " + var6.toString());
} catch (NoSuchMethodException var7) {
throw new RuntimeException("NoSuchMethodException: " + var7.toString());
}
}
}
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (!(o instanceof BeanComparator)) {
return false;
} else {
BeanComparator beanComparator = (BeanComparator)o;
if (!this.comparator.equals(beanComparator.comparator)) {
return false;
} else if (this.property != null) {
return this.property.equals(beanComparator.property);
} else {
return beanComparator.property == null;
}
}
}
public int hashCode() {
int result = this.comparator.hashCode();
return result;
}
}
- compare函数中涉及PropertyUtils,这是处理属性的一个相关类
- 关于compare函数的触发源自PriorityQueue在进行堆排序时,会自动调用compare函数
2. 关于JavaBean风格
在Java中,如果一个私有字段具有公开的读写方法,则称该class为JavaBean
(比如此例中的私有age参数,具有公开的getAge和setAge方法)
package JavaCode;
public class JavaBean {
private int age;
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
}
读方法也被统一称为getter方法,写方法也被统一称为setter方法。
定义JavaBean风格方便了IDE的代码补全。
调试分析
Gadget Chain
/* Gadget Chain
ObjectInputStream.readObject()
PriorityQueue.readObject()
PriorityQueue.heapify()
BeanComparator.compare()
PropertyUtils.getProperty()
PropertyUtilsBean.getProperty()
PropertyUtilsBean.getNestedProperty()
PropertyUtilsBean.getrSimpleProperty()
PropertyUtilsBean.invokeMethod()
...
TemplatesImpl动态加载恶意字节码
*/
调试过程
在进行PriorityQueue的readObject反序列化时,会进行一次堆排序,此时必然会触发compare函数。
- 老惯例,先看下调用栈
在PropertyUtilsBean中的getSimpleProperty中进行调用
- 首先进入compare函数,需要使用getter方法获取属性
注意在TemplatesImpl中有这个私有字段
- 在调用getter方法后,首先创建对象实例,然后调用getter方法获取bean对象的name属性的值进行返回
- 然后进入后需要继续调用getNestedProperty()
- 经过种种判断之后进入了getSimpleProperty
- 最后调用了invokeMethod实现了TemplatesImpl的恶意字节码加载完成了CB1链的攻击