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代碼塊。
至此也應該算是分析結束了。