freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Z3专栏 | CommonsCollections6分析
z3 2021-12-15 21:27:32 231979
所属地 辽宁省

六、CommonsCollections6

为什么CommonsCollections1后直接看CommonsCollections6了?
因为据说CommonsCollections1和CommonsCollections6很像,趁热打铁,把6也学了

分析

代码分析

先看下代码
CommonsCollections6的代码很长啊
先看一部分
红框内的代码在CommonsCollections1内已经学过了,构造了一个LazyMap对象,只要调用它的get方法,就会触发利用链
继续看下面代码
TiedMapEntry是什么?
看下构造函数
把map和key保存了
再继续看代码
创建了一个HashSet,容量为1,添加了个"foo"
然后看下一部分代码
(这里的try catch应该是为了兼容不同版本的jdk)
这部分代码看起来很多,其实很简单,简写就是下面这样

map.map.table[0].key=entry;
return map;

只不过因为有些成员变量是private类型,不能直接访问,这里用了反射的方式修改
继续分析下这些变量
HashSet的成员变量竟然有HashMap,看一下果然,成员变量有map
HashSet的add方法在添加新元素时,会把它设置为map的key,因为HashMap的key唯一嘛,所以HashSet将HashMap的key当做自己的元素,通过这种方式保证了HashSet没有重复元素(集合的特点之一)
再看下HashMap的table如图
table是Node类型数组,Node是HashMap的内部静态类
HashMap每添加一个新元素都会放在Node数组里
而Node类包含了map的hash,key,value等信息
好了,再回头看一下第二部分代码

map.map.table[0].key=entry;
return map;

这下理解了把,map是集合,内部通过字典的键来实现元素唯一的
那这句话

map.map.table[0].key=entry;

意思就是把map对象内的第一个元素值修改为entry呗
等下这是什么操作,
先再map内添加元素"foo",再把这个元素改为entry,那为什么不直接再map内添加entry?

调试分析反序列化过程

如图,先写个代码调试下
由于经过上面分析,我们已经知道了,最终肯定是由于调用了LazyMap的get方法,造成命令执行
那就直接再LazyMap的get方法上加个断点
启动,调试
果然是这里触发
看一下调用链
问题的根源在这里,HashSet有自己的readObject方法,它和HashMap同理,先创建个空的HashSet,再把元素一个个put进去
可以看见,这里put的元素正是之前构造的 TiedMapEntry对象
看下put时发生了什么
获取TiedMapEntry对象的hash
调用TiedMapEntry对象自己的hashCode方法
如图,调用了map的get方法,回想一下TiedMapEntry的构造函数,这个map是什么?
是LazyMap对象
调用了get方法,所以导致触发了命令执行

ok,至此,这条利用链原理弄清了

总结

这条利用链可以分为三部分
第一部分是构造LazyMap对象,调用get方法即可触发rce
第二部分是构造TiedMapEntry对象,TiedMapEntry的hashCode方法是同时调用key和map里key对应的value的hashCode方法,然后进行亦或,而在获取map的value时,调用了map的get方法
第三部分是构造HashSet对象,HashSet在反序列化时,调用map.put,put方法会调用key的hashCode方法
所以反序列化时->HashSet的put->TiedMapEntry的hashCode->LazyMap的get

疑问

为什么要先再HashSet对象内放个"foo",然后通过这么多反射,将这个元素修改为entry,直接添加entry不行吗?

测试下看看,write时弹计算器,read时没弹
问题出在哪了?
调试下看看
跟踪反序列化流程
到了调用LazyMap的get方法的时候,没通过if条件
因为map里已经有foo这个键了
为什么?创建LazyMap对象时明明是空的
回想一下代码,哪里最可能在map里添加了键值

map.add(entry);

只有这里嫌疑最大
看下add方法
在HashSet的map里将TiedMapEntry对象设置为key
这里没问题,没对TiedMapEntry对象做出修改
再看下put方法
这里就有问题了
回想一下,上面的总结,对TiedMapEntry对象计算hash,就会调用TiedMapEntry对象的hashCode方法,然后就会调用LazyMap的get方法
在上一篇学习LazyMap的时候分析过,它的get方法
键不存在,则会新建一个键值对

所以,问题就在这里
HashSet调用add添加的元素,会在LazyMap里添加一个和这个元素相同的key
则下次调用LazyMap的get方法时,不会创建新的键值对,也就不会调用Transformer链,不会造成rce

所以在构造payload时,不能使用HashSet的add方法添加构造好的map对象,要用反射修改

ok,至此,CommonCollection6结束了

# java漏洞 # java # java反序列化 # Java代码审计 # JAVA安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 z3 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
java代码审计学习
z3 LV.4
  • 27 文章数
  • 89 关注者
Java 反序列化回显链研究:漏洞检测工程化
2022-04-01
Z3专栏 | CommonsCollections3分析
2022-03-19
MeterSphere未授权导致的rce漏洞分析、复现、exp编写
2022-02-11
文章目录