前言
后面几条cc链和前面讲的有很多共通点,这里浅浅一起分析一手
CommonsCollections4
首先pom.xml导入依赖
1 | <dependency> |
cc3引入了InstantiateTransformer
类替换了InvokerTransformer
对cc1链进行变形绕过过滤。同理,cc2也能做同样的变形形成一条新的利用链,这就是cc4链。cc4相对于cc2来说并没有将TemplatesImpl
类的实例直接放入队列
反序列化调用链如下:
1 | PriorityQueue.readObject() |
第二次transform()
的时候即调用该类的newInstance()
实例化,而实例化的参数因为也是可控的,因此在参数位置放入TemplateImpl
类的实例
POC链为
1 | import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; |
CommonsCollections5
首先pom.xml导入依赖
1 | <dependency> |
和cc6链类似cc5这条链的外部入口变了,但里面没变,依然是和cc1链一样进到LazyMap.get()
然后调用Transformer数组进行RCE
反序列化调用链如下:
1 | BadAttributeValueExpException.readObject() |
TiedMapEntry#getValue()
方法调用了get()
,而且map在TiedMapEntry
类构造函数中可控
1 | public TiedMapEntry(Map map, Object key) { |
TiedMapEntry#toString
方法调用了getValue()
方法
1 | public String toString() { |
那么就要找哪里调用了toString
方法可以和readObject()
连起来,可以发现BadAttributeValueExpException
类的readObject()
方法
1 | private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
这里想办法让valObj
是TiedMapEntry
类的对象,valObj
的来源是
1 | ObjectInputStream.GetField gf = ois.readFields(); |
这里先调用readFields
从流中读取了所有的持久化字段,然后调用get()
方法得到了名字是val
的字段。这里可以用反射机制修改val的为TiedMapEntry
类的对象
PoC链
1 | import org.apache.commons.collections.Transformer; |
CommonsCollections7
首先pom.xml导入依赖
1 | <dependency> |
和cc5一样,cc7也是外部入口变了,都是换种姿势调用到LazyMap.get()
方法实现一系列调用
反序列化调用链为:
1 | Hashtable.readObject |
这条链子入口是Hashtable
类的readObject()
方法
1 | private void readObject(ObjectInputStream s) |
Entry是一个数据结构的类,这个类里存放了key和value。table是一个Entry数组,而且为空。这里会调用reconstitutionPut()
方法
1 | private void reconstitutionPut(Entry<?,?>[] tab, K key, V value) |
第一次调用reconstitutionPut()
,将key和value存入上面说的table中。然后若循环条件满足继续调用reconstitutionPut()
在if语句里调用了e.key.equals(key)
,也就是要构造两个Hashtable
类的对象并让map1和map2是LazyMap
类型,从而调用LazyMap.equals()
方法,但LazyMap
类里没有这个equals()
方法,寻找父类AbstractMapDecorator
实现的equals方法
1 | public boolean equals(Object object) { |
它去调用map属性的equals方法,这里的map其实是我们创建LazyMap时传入的HashMap
HashMap也没有equals方法,寻找父类AbstractMap
实现的equals方法
1 | public boolean equals(Object o) { |
这里的迭代器i其实是map1的entrySet()的迭代器,while循环里是拿到map1里的key和value;然后是m,这里的m其实是传递过来的map2,value不为空,所以他会走else,然后先调用m.get(key),实际就是LazyMap.get()
PoC链
1 | import org.apache.commons.collections.Transformer; |
参考链接:
Author: ph0ebus