站長資訊網
        最全最豐富的資訊網站

        java反序列化引發的遠程代碼執行漏洞原理分析

        java反序列化引發的遠程代碼執行漏洞原理分析

        主要有3個部分組成:

        1、Java的反省機制

        2、Java的序列化處理

        3、Java的遠程代碼執行

        Java的反射與代碼執行

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

        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包中導入Runtime類,之后調用其getRuntime方法得到1個Runtime對象,該對象可以用于JVM虛擬機運行狀態的處理。接著我們調用其exec方法,傳入1個字符串作為參數。

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

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

        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個字符串作為參數,其返回1個Class的實例。而其作用是根據對應的名稱找到對應的類。

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

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

        之后通過得到的方法的實例的invoke方法調用對應的類方法,由于沒有參數則傳入null即可。同理,我們再獲取到exec方法。

        Java序列化處理

        對于Java中的序列化處理,對應的類需要實現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個函數是serialize和deserialize,分別用于序列化和反序列化處理。

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

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

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

        java反序列化引發的遠程代碼執行漏洞原理分析

        Java遠程通信與傳輸

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

        首先是服務器端,監聽本地的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個服務器的socket,之后調用其accept方法接收客戶端的請求。此時,得到了1個socket對象,而通過socket對象的getInputStream方法獲取輸入流,并指定1個長度為1024的字節數組。

        接著調用socket的read方法讀取那么指定長度的字節序列,之后通過String構造器將字節數組轉換為字符串并輸出。這樣我們就得到了客戶端傳輸的內容。

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

        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方法獲取到輸出流,用于往服務器端發送輸出。由于這里只是演示,使用的是本地的主機IP。而在實際應用中,如果我們知道某個外網主機的IP及開放的端口,如果當前主機存在對應的漏洞,也是可以利用類似的方式來實現的。

        這里我們設置要傳輸的內容為UTF-8編碼的字符串,俄日在輸出流的write方法中通過字符串的getBytes指定其編碼,從而將其轉換為對應的字節數組進行發送。

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

        Server is waiting for connect Hello,Java Socket Server

        Java反序列化與遠程代碼執行

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

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

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

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

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

        我們在接收到客戶端對應的字符串后對其進行反序列處理,之后調用某個指定的函數,從而實現遠程代碼的執行。而在客戶端,我們需要對其進行序列化處理:

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

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

        java反序列化引發的遠程代碼執行漏洞原理分析

        可以看到,我們成功的在宿主機器上執行了對應的命令執行。

        總結

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

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

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

        推薦相關文章教程:web安全教程

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 久久久久四虎国产精品| 99RE8这里有精品热视频| 国产精品18久久久久久vr| 亚洲国产成人精品久久久国产成人一区二区三区综 | 亚洲国产成人久久精品影视| 精品无码无人网站免费视频| 亚洲а∨天堂久久精品| 精品中文高清欧美| 国产精品无码素人福利不卡| 91精品久久久久久无码| 国产精品嫩草视频永久网址| 国产成人精品手机在线观看| 少妇人妻偷人精品视频| 中文无码久久精品| 中文字幕精品久久久久人妻| 四虎国产精品免费久久| 精品视频久久久久| 精品国产一区二区三区AV性色| 欧美精品免费线视频观看视频| 97视频在线观看这里只有精品| 精品乱码一区二区三区四区| 人妻精品久久久久中文字幕69 | 无码人妻精品一区二区三区99不卡 | 高清在线亚洲精品国产二区| 久久精品国产网红主播| 亚洲日韩一页精品发布| 真实国产精品vr专区| 日本一区二区三区精品国产 | 国产精品九九九久久九九| 国产精品无码午夜福利| 精品亚洲麻豆1区2区3区| 国产欧美日韩精品丝袜高跟鞋| 久久ww精品w免费人成| 久久精品国产影库免费看| 国产在线精品免费aaa片| 亚洲国产小视频精品久久久三级 | 久久九九精品99国产精品| 亚洲精品乱码久久久久久中文字幕| 无码乱码观看精品久久| 亚洲精品A在线观看| 在线精品国产一区二区三区|