Commons-Collections02-cc6链
- 相关链接
https://drun1baby.top/2022/06/11/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Commons-Collections%E7%AF%8703-CC6%E9%93%BE/
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections6.java
环境配置部分不做过多赘述,详细可以见 cc1链的环境配置过程。
cc1 链补充
在 jdk1.8.0_u71版本下,AnnotationInvocationHandler 中已经对 readObject 类进行了修复
所以对于 LazyMap 的动态代理利用链,以及 TransformedMap 利用链都已经用不了了。
cc6 链分析
比 cc1 链较好,可以不受 jdk 版本限制。
尾部 exec 链
可以看到 exec 的链子依旧是和 cc1 链一样的
LazyMap.get() -> ChainedTransformer -> InvokerTransformer
1 | org.apache.commons.collections.map.LazyMap.get() |
所以我们直接从 LazyMap 开始分析
寻找利用链
我们知道 URLDNS 利用链中是通过 HashMap 的 get 方法
调用 hash 方法。对传入的 key 调用 key 中的 hashCode 方法
那如果说,有一个类中存在 xxx.hashcode 方法,并且该方法中可以去调用到 xxx.get
那我们把 xxx.get 改为 LazyMap.get ,是不是就可以调用后续的链子了?
还真是
TiedMapEntry 中就有一个方法,会调用 getValue 方法。
而 getValue 又调用了 map.get(key)
map 需要为 LazyMap , key 则为 Runtime.getRuntime()]
利用链非常的清晰。
但是还是要从 LazyMap 开始写起,熟能生巧。多写几遍不会有坏处
通过反射直接调用 LazyMap 的 get 方法弹 calc
1 | Runtime runtime = Runtime.getRuntime(); |
然后将反射改为从 TiedMapEntry 调用:
1 | TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, runtime); |
没问题
接下来就是通过 HashMap 去调用
1 | TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, runtime); |
但是这里有两个问题
- Runtime 不能被序列化(可以解决,最后只需要用 InvokerTransformer 拿就行)
- 序列化的时候也可以触发 map2.put
解决序列化的时候也可以触发问题
之前在 URLDNS 中遇到过
我们只需要在序列化之前修改 put 中的 key 状态不足以触发当前攻击连即可。
那我们就修改 LazyMap 的 decorate 方法。
最开始把 factory 的值改为不指向 chainedTransformer ,我们传入 new ConstantTransformer(1)
让 HashMap put 前的链子执行不了。
然后 put 后再给 factroy 的值改回来。
因为 factory 是 protected 的
1 | protected final Transformer factory; |
所以我们要通过反射的方法来进行修改
1 | LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, new ConstantTransformer(1)); |
(此处有问题,Line 41 map2.put(xxx) 应该在反射代码修改前,不想重新再截图了 T T)
(此处有问题,Line 23 最后应该还有一个 null 参数,为 "getRuntime", null ,不想重新再截图了 T T)
序列化后进行反序列化,但是发现计算器并没有弹出
我们在 map2.put(tiedMapEntry, "junk"); 处下断点进行调试
走到:
既然已经存在 key junk ,那么我们在序列化之前手动把该 key 删除
那这样反序列化的时候 key 就不存在了,就可以正常走到 if 分支中。
1 | lazyMap.remove("junk"); // 序列化之前操作 |
至于为什么是 lazyMap 中 remove,各位师傅可以去 debug 后查看。
总结
总给人一种感觉:
cc1 + URLDNS = cc6流程:
HashMap.put()
-> TiedMapEntry.hashCode()
-> TiedMapEntry.getValue()
-> LazyMap.get() <- 需要修改确保序列化的时候不执行攻击连
-> chainedTransformer.transform(xxx);- ConstantTransformer(Runtime.class)
- runTime
- invoke
- exec(“calc”)
完整 exp:
1 | package xekoner; |
- 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.