Commons-Collections做为 Java 集合的扩展,增加了很多功能各异的集合 和 Map,对于实现一些特殊的需求来说是很方便的。
可以看到之前的Commons-Collections3版本 <groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
以及停止在了2015,后面还在跟新的是commons-collections4<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
他们的artifactId和groupId都不一样,commons-collections4不再认为是⼀个用来替换commons-collections的新版 本,而是⼀个新的包,两者的命名空间不冲突,因此可以共存在同⼀个项目中。
commons-collections4包的改动
添加依赖
1 | <dependency> |
把cc6拿来看看,将所有 import org.apache.commons.collections.*
改成 import org.apache.commons.collections4.*
摁住alt就可以整列添加
看到飘红了,LazyMap.decorate 这个⽅法没了。
decorate是LazyMap构造函数的⼀个包装,在4中改了个名字叫 lazyMap
运行后成功弹出计算器
CommonsCollections2利用链
commons-collections这个包利用链多不仅是利用量大,还有原因是其中包含了⼀些可以执行任意⽅法的Transformer。
其中⽤到的两个关键类是:
java.util.PriorityQueue
org.apache.commons.collections4.comparators.TransformingComparator
java.util.PriorityQueue
基于优先级堆的无界优先级队列。优先级队列的元素根据其自然顺序排序,或者由队列构建时提供的Comparator排序,具体取决于使用的是哪个构造函数。
添加到 PriorityQueue 队列里面的元素都经过了排序处理,默认按照自然顺序,也可以通过 Comparator 接口进行自定义排序。优先队列的作用是保证每次取出的元素都是队列中权值最小的。
你应该知道的 PriorityQueue ——深入浅出分析 PriorityQueue - 知乎 (zhihu.com)
他有自己的readObject() 方法
1 | private void readObject(java.io.ObjectInputStream s) |
排序是靠将⼤的元素下移实现的。 siftDown()
是将节点下移的函数,comparator.compare()
用来比较两个元素大小 TransformingComparator
实现了 java.util.Comparator
接⼝,这个接⼝⽤于定义两个对象如 何进⾏⽐较。 siftDownUsingComparator()
中就使⽤这个接⼝的 compare()
⽅法⽐较树的节点。
org.apache.commons.collections4.comparators.TransformingComparator
有调用 transform() 方法的函数
1 | public int compare(I obj1, I obj2) { |
这样就可以从PriorityQueue 到 TransformingComparator 构造利用链。
利用链
1 | ObjectInputStream.readObject() |
第一步创建Transformer来执行命令。
第二步创建⼀个TransformingComparator ,传⼊我们的Transformer
1 | Comparator comparator = new TransformingComparator(transformerChain); |
第三步实例化 PriorityQueue 对象,第⼀个参数是初始化时的⼤⼩,⾄少需要2个元素才会触发排序和⽐较, 所以是2;第⼆个参数是⽐较时的Comparator,传⼊前⾯实例化的comparator:
1 | PriorityQueue queue = new PriorityQueue(2, comparator); |
传入的数值必须为非null
最后,将真正的恶意Transformer设置上
1 | setFieldValue(transformerChain, "iTransformers", transformers); |
完整POC
1 | import java.io.ByteArrayInputStream; |
用TemplatesImpl进行改造
首先创建TemplatesImpl
对象
1 | TemplatesImpl obj = new TemplatesImpl(); |
创建InvokerTransformer
对象,并⽤它实例化 Comparator (打CTF又可能用其他来实例化 Comparator):
1 | Transformer transformer = new InvokerTransformer("toString", null, null); |
接着向队列⾥添加的元素就是我们前⾯创建的 TemplatesImpl 对象,⽆法再使⽤Transformer数组,所以也就不能 ⽤ ConstantTransformer 来初始化变量,需要接受外部传⼊的变量。
1 | PriorityQueue queue = new PriorityQueue(2, comparator); |
最后⼀步,将 toString ⽅法改成恶意⽅法 newTransformer
1 | setFieldValue(transformer, "iMethodName", "newTransformer"); |
poc
1 | import java.io.ByteArrayInputStream; |
CommonsCollections4利用链
在CC3包装到ChainedTransformer时,再接上CC2中的PriorityQueue链。
TransformingComparator
这个类的compare方法调用了transformer方法可以进行执行命令
构造思路
- 创建Templates链
- 将templates包装成ChainedTransformer
- 创建一个TransformingComparator类,其this.transformer要为步骤二中的chain
- 创建一个PriorityQueue,其comparator为步骤三中的TransformingComparator
完整poc
1 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; |
总结
CC链就先告一段落了,其他利用链应该大同小异用的现学也来的及吧。看到一张图总结得很好
参考: