技术社区
安全培训
技术社群
积分商城
先知平台
漏洞库
历史记录
清空历史记录
相关的动态
相关的文章
相关的用户
相关的圈子
相关的话题
注册
登录
Java 反序列化:Apache Commons Collections CC6 利用链深度解析
b1uel0n3
发表于 中国
漏洞分析
495浏览 · 2025-06-26 11:38
返回文档
环境搭建
●
jdk 8u71
●
Commons Collection 3.2.1
jdk下载地址:
https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html#license-lightbox
具体搭建流程与CC1链是一样的,可以看我之前的
文章
。注意CC6对jdk是不受版本限制的,所以任意版本都行,但Commons Collection版本要小于等于3.2.1
前言
回顾
CC1
:
1
TransformedMap链中,我们是先通过
sun.reflect.annotation.AnnotationInvocationHandler
类中的readObject方法,然后foreach语句会执行Map遍历,执行
memberValues.setValue()
方法,从而调用
MapEntry.setValue()
,然后执行
TransformedMap.checkSetValue()
来触发ChainedTransformer的transform方法。
2
而在LazyMap链中,则是在foreach语句执行
memberValues.entrySet()
,此时会相当于调用代理对象触发
sun.reflect.annotation.AnnotationInvocationHandler
类中的
invoke()
方法,然后调用
LazyMap.get()
方法来触发ChainedTransformer的transform方法。
但自从Java 8u71以后,官方修改了AnnotationInvocationHandler类中的readObject方法,修改后的代码可以看到不再使用我们原始的Map对象,而是新建了LinkedHashMap对象,并将键值对加入,使得后续操作都是针对于这个新的LinkedHashMap对象,使得无法触发
LazyMap.get()
方法,且新的方法也没有了
memberValues.setValue()
了,可以说TransformedMap链没法用了。
所以我们就思考能否找到一条不经过AnnotationInvocationHandler类且能够触发LazyMap.get()方法的链子呢?
CC6分析
HashMap链分析
通过搜索,恰好发现TiedMapEntry中的getValue()方法能调用map.get(),而且map是可控的:
那么我们就能通过getValue()来调用LazyMap.get(),搜索getValue()看哪些方法调用了它:
发现该类中hashCode方法可以调用它,那么就好办了,hashCode方法我们并不陌生,URLDNS链就是利用HashMap的readObject方法调用putVal()方法,然后调用hash(key),最后调用key.hashCode()方法:
所以我想着试一下能否可行,先通过TiedMapEntry.getValue()调用LazyMap.get():
然后通过HashMap.readObject()调用TiedMapEntry.hashCode从而调用TiedMapEntry.getValue,而readObject中key是我们可控的,我们可以通过put()方法传入key:
但这里有个问题,学过URLDNS链的师傅都知道,Map.put()方法也是会调用hashCode()方法的:
跟HashMap.readObject()调用的方式是一样的,所以执行到这时不用反序列化也能触发TiedMapEntry.hashCode方法弹计算机:
而当最后执行反序列化时:
虽然弹了计算机,但通过打断点知道其实执行在执行readObject方法前就已经报错了,并没有执行readObject方法,猜测是因为执行put方法时触发hashCode执行了一次exec命令,而exec返回一个Process对象到Map中从而报错
为了防止这么情况,我们可以先向LazyMap.decorate()传入一个假的ChainedTransformer,这样就算执行put也不会触发exec,然后执行后利用反射将ChainedTransformer改为我们要利用的ChainedTransformer,从而达到我们的效果。
修改后的poc:
新添加的new ConstantTransformer(1)有隐蔽启动进程日志的作用,也可以不加
虽然现在不会报错了,但也没有弹出计算机
在HashMap.readObject处下断点:
可以看到这并不是我们想要的类型的key,而这个key是我们
TiedMapEntry tiedMapEntry=new TiedMapEntry(Lazymap,"b1uel0n3");
传入的,但奇怪的是,当我将值改为
111
等数字时,突然就弹计算机了:
可以看到这时的key又是TiedMapEntry类型了。
这就令我有点疑惑,为什么会这样呢?于是我就问ai,还是代码的问题:
大家可以想一下上面两种写法哪种更好?
第一种将 TiedMapEntry 放入被 LazyMap 装饰的 map 中,而这个就有个问题就是逻辑有些混乱:
可以看到已经形成了循环引用:map 包含 entry,entry 又指向 LazyMap,而 LazyMap 又装饰 map。这就会导致键值污染,即当触发反序列化时LazyMap 已被部分初始化(有键值对)而出现问题
而第二种则是将 TiedMapEntry 放入独立的 map1 中:
这样不仅逻辑清晰,且map完全干净,则不会出现上诉问题
所以我们修改下代码:
但依旧没有弹计算机,下个断点看看:
那为什么会这样呢,于是我重新看了下每个方法的利用条件,而当我看到LazyMap.get()方法时:
只有当访问不存在的键时才会调用,而执行
TiedMapEntry tiedMapEntry=new TiedMapEntry(Lazymap,"111");
时其实已经设置了键,我们重新理一遍:
当反序列化时会调用HashMap.readObject():
其中key为
tiedMapEntry
对象,value为"b1uel0n3",然后调用
HashMap.hash(key)
,触发
key.hashCode()
,即
tiedMapEntry.hashCode()
,tiedMapEntry中map为
LazyMap
,key为"111",调用
tiedMapEntry.getValue(key)
,然后触发
map.get(key)
,即LazyMap.get("111")。但有个问题,
map.containsKey(key) == false
才调用transform方法,即不存在这个键才能访问,而
TiedMapEntry tiedMapEntry=new TiedMapEntry(Lazymap,"111");
将键存在了LazyMap的map中
所以我们需要把它移除才能触发LazyMap.get()方法:
成功弹出计算机
最终poc:
完整利用链:
HashSet链分析
ysoserial
给的链子是HashSet链:
对比HashCode链可以看出这条链依旧是通过
TiedMapEntry.hashCode()->TiedMapEntry.getValue()
来调用LazyMap.get(),但唯一不同的是触发TiedMapEntry.hashCode()是通过HashMap.put()来触发。正如前面我们提到的,HashMap.put()和HashMap.readObject()最后都是调用
putVal(hash(key))
,都能触发
TiedMapEntry.hashCode()
。
但HashMap.put()我们最后是能触发LazyMap.get(),但我们还需要一个起点,于是我们搜索
map.put(
,成功找到HashSet.readObject():
恰好HashSet类中readObject方法恰好调用了map.put(),而且map也正是我们想要的HashMap对象,同时HashSet是可序列化的。但还有个问题,虽然我们能触发Hash.put()方法了,但我们是通过HashMap.put()->HashMap.hash(key)->HashMap.key.hashCode()。所以我们还需要key可控,即e可控:
而HashSet提供了add方法,这样就使得e可控了:
但依旧存在问题,可以看到,就算我们不进行反序列化依旧能弹计算机,这是因为
map.add(tiedMapEntry);
传入tiedMapEntry对象后,而恰好add里面有和readObject的map.put()方法,于是直接把我们的链子走了一遍,弹了计算机。
解决这个问题的思路和HashMap链是一样的,就是通过先在tiedMapEntry对象中传入一个假payload的LazyMap对象,然后执行完add方法添加了e后再通过反射将payload改回去,即改字段iTransformers的值。
最终poc:
注意LazyMap.get()执行的条件,
innermap.remove("b1uel0n3");
键名不存在时触发,也是成功弹计算机了
完整利用链:
参考
https://changeyourway.github.io/2024/05/13/Java%20%E5%AE%89%E5%85%A8/%E6%BC%8F%E6%B4%9E%E7%AF%87-CC6%E9%93%BE%E5%88%86%E6%9E%90/
https://nivi4.notion.site/Java-CommonCollections6-b3a2ddf3ab16403699363c2ede802fcb
https://www.freebuf.com/articles/web/336628.html
https://curlysean.github.io/2025/02/24/CC6%E9%93%BE/
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections6.java
0
人收藏
1
人喜欢
转载
分享
0
条评论
某人
表情
可输入
255
字
评论
发布投稿
热门文章
1
cyberstrikelab-shadow靶场首杀
2
从零开始手搓C2框架
3
契约锁电子签章系统 pdfverifier rce 前台漏洞分析(从源码分析)
4
大华智能物联管理平台1day分析
5
契约锁电子签章系统 pdfverifier 远程代码执行漏洞分析(补丁包逆向分析)
近期热点
一周
月份
季度
1
cyberstrikelab-shadow靶场首杀
2
从零开始手搓C2框架
3
契约锁电子签章系统 pdfverifier rce 前台漏洞分析(从源码分析)
4
大华智能物联管理平台1day分析
5
契约锁电子签章系统 pdfverifier 远程代码执行漏洞分析(补丁包逆向分析)
暂无相关信息
暂无相关信息
优秀作者
1
T0daySeeker
贡献值:41700
2
一天
贡献值:29800
3
Yale
贡献值:25000
4
1674701160110592
贡献值:21800
5
1174735059082055
贡献值:16000
6
手术刀
贡献值:14000
7
Loora1N
贡献值:13000
8
bkbqwq
贡献值:12800
9
Ha1ey
贡献值:11000
10
lufei
贡献值:11000
目录
环境搭建
前言
CC6分析
HashMap链分析
HashSet链分析
参考
转载
标题
作者:
你好
http://www.a.com/asdsabdas
文章
转载
自
复制到剪贴板