jdk 1.7,jdk1.8也测试成功。
Commons Collections 4.0
idea
idea创建maven项目,在pom.xml添加即可
后半段链和cc1差不多,正向分析,从readObject方法开始分析。
找到关键类<code>java.util.PriorityQueue</code>的readObject方法。

可以看到方法比较简单。可以看到queue[i]的值是由s.readObject方法得到的。为什么会这样,这是因为序列化的时候依次对queue[i]中的值进行序列化了,如下图。所以当反序列化的时候,也依次进行了反序列化。
既然这样的话,只要我们通过反射实例化PriorityQueue类的对象,并且给queue赋值即可,,实现了queue[i]控制。
接下来进入<code>heapify</code>方法
跟进<code>siftDown</code>方法,注意这里在第二个参数传入了queue[i],并且还要注意,这里进入for循环需要一个条件,就是size>1,因为<code>size >>> 1</code>进行了右移位操作,所以只有当size>1的时候才会进入循环,这是第一个条件。
这里的x即为queue[i],跟进<code>siftDownUsingComparator</code>方法。
重点在<code>comparator.compare(x, (E) c)</code>,comparator其实是一个Comparator接口,而<code>org.apache.commons.collections4.comparators.TransformingComparator</code>实现了<code>Comparator</code>接口,重写了<code>compare</code>方法,
可以看到compare方法中执行了<code>this.transformer.transform</code>。后面就是CC1链了。
分析几个关键地方
1.这里为了add了两个值主要是为了上面说到的第一个条件,size>1
2.必须在add后,再反射设置<code>comparator</code>值。
这是由于在add方法中调用了offer方法。
offer方法中调用了siftUp方法
在siftUp方法中,需要让<code>comparator</code>为null,才会走else,走else才可以添加到queue中,否则会报错。
在yso中用的CC2涉及到了另一个点:<code>TemplatesImpl</code>。jdk1.7和1.8都测试成功。
需要先去大概了解一下上面是<code>javassit</code>。
想了半天,最终还是从readObject来学习<code>TemplatesImpl</code>这条链。然后配合Poc中的代码结合来理解。
先放出完整的exp,虽然不是yso的实际代码,但原理是一样的。
我们最终序列化的是PriorityQueue的对象。所以从PriorityQueue的readObject方法来说起。
找到该方法。
注意图中的<code>queue</code>变量,这个变量我们已经在exp中修改过值了。对应的exp如下。
由此可知,queue里有两个值,第一个值是<code>templates</code>,第二个值是<code>1</code>。
并且<code>size</code>变量也已经在exp中修改了,对应exp代码如下,将size修改为2。至于为什么我觉得应该不用说了,上面已经解释过了。
跟进<code>heapify</code>方法,
跟进<code>siftDown</code>方法,传入了queue[i],
在这里遇到了<code>comparator</code>变量,对应的exp代码如下。
而comparator如下对应exp代码如下
继续跟进<code>siftDownUsingComparator</code>方法。
关键代码<code>comparator.compare</code>,通过前面的分析可知,这里的<code>comparator</code>是TransformingComparator实例化的对象,而变量x是queue[0],因为在<code>heapify</code>函数中是依次循环的,而queue[0]是exp中的<code>templates</code>,仔细对照上面的分析及exp代码。
接下来则调用的是<code>TransformingComparator</code>的<code>compare</code>方法
跟踪该方法。
注意看这里的<code>this.transformer</code>对应的exp代码是,即<code>this.transformer</code>就是exp代码中的<code>transformer</code>。(注意实例化的时候传了一个参数为"newTransformer"。)
即调用了<code>InvokerTransformer</code>的<code>transform</code>方法,而<code>obj1</code>就是上面的<code>x</code>,即<code>templates</code>,
跟踪这个<code>transform</code>方法,
这里分析一下:
input变量就是上面的obj1,即传过来的<code>templates</code>,而this.iMethodName的值为<code>newTransformer</code>。因为<code>templates</code>是<code>TemplatesImpl</code>类的对象,所以调用的是<code>TemplatesImpl.newTransformer</code>。
跟踪<code>TemplatesImpl.newTransformer</code>方法。
跟踪<code>getTransletInstance</code>方法
图中,我们看到三处地方,第一处对应的exp代码如下,想必大家都知道为什么。只要不为null就好。
第二处,必须是null,因为我们想要进入<code>defineTransletClasses</code>方法。
第三处<code>_class[_transletIndex].newInstance();</code>会执行我们构造的static代码块,后面会说到。
跟进<code>defineTransletClasses</code>方法
可以看到<code>_bytecodes</code>变量,这个变量对应exp代码如下,
这么多代码就是通过javassti新建一个类,并且添加了一个static代码块,内容为<code>java.lang.Runtime.getRuntime().exec("calc.exe");</code>。如下图,这就是我们通过javassti生成的class文件。只不过在代码中,将该class转为了字节数组,即<code>_bytecodes</code>变量。
继续看<code>defineTransletClasses</code>方法
可以看到,上面已经将<code>_bytecodes</code>数组变成一个类了,后面判断该类的父类是否是<code>ABSTRACT_TRANSLET</code>,看下图,值为<code>com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet</code>。
所以我们要在exp代码中
因为我们要进入if判断,才能执行<code>_transletIndex = i;</code>,赋值给<code>_transletIndex</code>后,<code>_class[_transletIndex].newInstance();</code>才会执行我们恶意的static代码块。
至此也应该算是分析结束了。