久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      java反序列化引發(fā)的遠程代碼執(zhí)行漏洞原理分析

      java反序列化引發(fā)的遠程代碼執(zhí)行漏洞原理分析

      主要有3個部分組成:

      1、Java的反省機制

      2、Java的序列化處理

      3、Java的遠程代碼執(zhí)行

      Java的反射與代碼執(zhí)行

      我們先看個簡單的例子,使用Java調(diào)用計算器程序:

      import java.io.IOException; import java.lang.Runtime; public class Test {     public static void main(String[] args) {         Runtime env = Runtime.getRuntime();         String cmd = "calc.exe";             try {             env.exec(cmd);         } catch (IOException e) {             e.printStackTrace();         }     } }

      我們從java.lang包中導(dǎo)入Runtime類,之后調(diào)用其getRuntime方法得到1個Runtime對象,該對象可以用于JVM虛擬機運行狀態(tài)的處理。接著我們調(diào)用其exec方法,傳入1個字符串作為參數(shù)。

      此時,將啟動本地計算機上的計算器程序。

      下面我們通過Java的反省機制對上述的代碼進行重寫。通過Java的反省機制可以動態(tài)的調(diào)用代碼,而逃過一些服務(wù)端黑名單的處理:

      import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;  public class Test {      public static void main(String[] args) {         try {             Class<?> cls = Class.forName("java.lang.Runtime");                         String cmd = "calc.exe";             try {                 Method getRuntime = cls.getMethod("getRuntime", new Class[] {});                                 Object runtime = getRuntime.invoke(null);                 Method exec = cls.getMethod("exec", String.class);                 exec.invoke(runtime, cmd);             } catch (NoSuchMethodException e) {                 e.printStackTrace();             } catch (SecurityException e) {                 e.printStackTrace();             } catch (IllegalAccessException e) {                 e.printStackTrace();             } catch (IllegalArgumentException e) {                 e.printStackTrace();             } catch (InvocationTargetException e) {                 e.printStackTrace();             }         } catch (ClassNotFoundException e1) {             e1.printStackTrace();         }     } }

      上述代碼看起來很繁瑣,實際上并不是很難。首先,通過Class.forName傳入1個字符串作為參數(shù),其返回1個Class的實例。而其作用是根據(jù)對應(yīng)的名稱找到對應(yīng)的類。

      接著我們使用Class實例的getMethod方法獲取對應(yīng)類的getRuntime方法,由于該類沒有參數(shù),因此可以將其設(shè)置為null或使用匿名類來處理。

      Method getRuntime = cls.getMethod("getRuntime", new Class[] {});

      之后通過得到的方法的實例的invoke方法調(diào)用對應(yīng)的類方法,由于沒有參數(shù)則傳入null即可。同理,我們再獲取到exec方法。

      Java序列化處理

      對于Java中的序列化處理,對應(yīng)的類需要實現(xiàn)Serializable接口,例如:

      import java.io.Serializable; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class Reader implements Serializable {     private static final long serialVersionUID = 10L;         private void readObject(ObjectInputStream stream) {         System.out.println("foo...bar...");     }    public static byte[] serialize(Object obj) {        //序列化對象         ByteArrayOutputStream out = new ByteArrayOutputStream();         ObjectOutputStream output = null;             try {             output = new ObjectOutputStream(out);             output.writeObject(obj);             output.flush();             output.close();          } catch (IOException e) {             e.printStackTrace();         }        return out.toByteArray();      }    public static Object deserialize(byte[] bytes) {        //反序列化處理         ByteArrayInputStream in = new ByteArrayInputStream(bytes);         ObjectInputStream input;         Object obj = null;             try {             input = new ObjectInputStream(in);             obj = input.readObject();         } catch (IOException e) {             e.printStackTrace();         } catch (ClassNotFoundException e) {             e.printStackTrace();         }        return obj;      }         public static void main(String[] args) {             byte[] data = serialize(new Reader()); //對類自身進行序列化         Object response = deserialize(data);         System.out.println(response);     } }

      在這里我們重寫了該類的readObject方法,用于讀取對象用于測試。其中比較重要的2個函數(shù)是serialize和deserialize,分別用于序列化和反序列化處理。

      其中,serialize方法需要傳入1個對象作為參數(shù),其輸出結(jié)果為1個字節(jié)數(shù)組。在該類中,其中的對象輸出流ObjectOutputStream主要用于ByteArrayOutputStream進行包裝,之后使用其writeObject方法將對象寫入進去,最后我們通過ByteArrayOutputStream實例的toByteArray方法得到字節(jié)數(shù)組。

      而在deserialize方法中,需要傳入1個字節(jié)數(shù)組,而返回值為1個Object對象。與之前的序列化serialize函數(shù)類似,此時我們使用ByteArrayInputStream接收字節(jié)數(shù)組,之后使用ObjectInputStream對ByteArrayInputStream進行包裝,接著調(diào)用其readObject方法得到1個Object對象,并將其返回。

      當我們運行該類時,將得到如下的結(jié)果:

      java反序列化引發(fā)的遠程代碼執(zhí)行漏洞原理分析

      Java遠程通信與傳輸

      為了實現(xiàn)Java代碼的遠程傳輸及遠程代碼執(zhí)行,我們可以借助RMI、RPC等方式。而在這里我們使用Socket進行服務(wù)端及客戶端處理。

      首先是服務(wù)器端,監(jiān)聽本地的8888端口,其代碼為:

      import java.net.Socket; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; public class Server {     public static void main(String[] args) throws ClassNotFoundException {             int port = 8888;             try {             ServerSocket server = new ServerSocket(port);             System.out.println("Server is waiting for connect");             Socket socket = server.accept();             InputStream input = socket.getInputStream();                         byte[] bytes = new byte[1024];             int length = 0;                         while((length=input.read(bytes))!=-1) {                 String out = new String(bytes, 0, length, "UTF-8");                 System.out.println(out);             }             input.close();             socket.close();             server.close();         } catch (IOException e) {             e.printStackTrace();         }     } }

      我們通過傳入1個端口來實例化ServerSocket類,此時得到1個服務(wù)器的socket,之后調(diào)用其accept方法接收客戶端的請求。此時,得到了1個socket對象,而通過socket對象的getInputStream方法獲取輸入流,并指定1個長度為1024的字節(jié)數(shù)組。

      接著調(diào)用socket的read方法讀取那么指定長度的字節(jié)序列,之后通過String構(gòu)造器將字節(jié)數(shù)組轉(zhuǎn)換為字符串并輸出。這樣我們就得到了客戶端傳輸?shù)膬?nèi)容。

      而對于客戶端器,其代碼類似如下:

      import java.io.IOException; import java.net.Socket; import java.io.OutputStream; public class Client {     public static void main(String[] args) {         String host = "192.168.1.108";                 int port = 8888;         try {             Socket socket = new Socket(host, port);             OutputStream output = socket.getOutputStream();             String message = "Hello,Java Socket Server";             output.write(message.getBytes("UTF-8"));             output.close();             socket.close();         } catch (IOException e) {             e.printStackTrace();         }     } }

      在客戶端,我們通過Socket對象傳遞要連接的IP地址和端口,之后通過socket對象的getOutputStream方法獲取到輸出流,用于往服務(wù)器端發(fā)送輸出。由于這里只是演示,使用的是本地的主機IP。而在實際應(yīng)用中,如果我們知道某個外網(wǎng)主機的IP及開放的端口,如果當前主機存在對應(yīng)的漏洞,也是可以利用類似的方式來實現(xiàn)的。

      這里我們設(shè)置要傳輸?shù)膬?nèi)容為UTF-8編碼的字符串,俄日在輸出流的write方法中通過字符串的getBytes指定其編碼,從而將其轉(zhuǎn)換為對應(yīng)的字節(jié)數(shù)組進行發(fā)送。

      正常情況下,我們運行服務(wù)器后再運行客戶端,在服務(wù)器端可以得到如下輸出:

      Server is waiting for connect Hello,Java Socket Server

      Java反序列化與遠程代碼執(zhí)行

      下面我們通過Java反序列化的問題來實現(xiàn)遠程代碼執(zhí)行,為了實現(xiàn)遠程代碼執(zhí)行,我們首先在Reader類中添加1個malicious方法,其代碼為:

      public Object malicious() throws IOException {         Runtime.getRuntime().exec("calc.exe");         System.out.println("Hacked the Server...");                 return this;     }

      在該方法中我們使用之前的介紹調(diào)用宿主機器上的計算器程序,然后輸出1個相關(guān)信息,最后返回當前類。

      之后是對服務(wù)器端的代碼進行如下的修改:

      while((length=input.read(bytes))!=-1) {     Reader obj = (Reader) Reader.deserialize(bytes);     obj.malicious(); }

      我們在接收到客戶端對應(yīng)的字符串后對其進行反序列處理,之后調(diào)用某個指定的函數(shù),從而實現(xiàn)遠程代碼的執(zhí)行。而在客戶端,我們需要對其進行序列化處理:

      Reader reader = new Reader(); byte[] bytes = Reader.serialize(reader); String message = new String(bytes); output.write(message.getBytes());

      下面我們在宿主機器上運行服務(wù)器端程序,之后在本地機器上運行客戶端程序,當客戶端程序執(zhí)行時,可以看到類似如下的結(jié)果:

      java反序列化引發(fā)的遠程代碼執(zhí)行漏洞原理分析

      可以看到,我們成功的在宿主機器上執(zhí)行了對應(yīng)的命令執(zhí)行。

      總結(jié)

      為了實現(xiàn)通過Java的反序列問題來實現(xiàn)遠程代碼執(zhí)行的漏洞,我們需要編寫1個有惡意代碼注入的序列化類。之后在客戶端將惡意代碼序列化后發(fā)送給服務(wù)器端,而服務(wù)器端需要調(diào)用我們期望的方法,從而觸發(fā)遠程代碼執(zhí)行。

      為了避免服務(wù)器端進行一些安全處理,我們可以采用反射的方式來逃逸其處理。

      這里只是1個簡化的過程,更加實用的過程可以參考Apache Common Collections的問題導(dǎo)致的Weblogic漏洞CVE-2015-4852及Jboss的漏洞CVE-2015-7501。

      推薦相關(guān)文章教程:web安全教程

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號