

攻击Java中的JNDI、RMI、LDAP(一)
source link: https://y4er.com/post/attack-java-jndi-rmi-ldap-1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

攻击Java中的JNDI、RMI、LDAP(一)
2020-03-05学习JNDI、RMI、JRMP
关于JNDI
JNDI(Java Naming and Directory Interface)是Java提供的Java 命名和目录接口。通过调用JNDI的API应用程序可以定位资源和其他程序对象。JNDI是Java EE的重要部分,需要注意的是它并不只是包含了DataSource(JDBC 数据源),JNDI可访问的现有的目录及服务有:JDBC、LDAP、RMI、DNS、NIS、CORBA,摘自百度百科。
命名服务的相关概念:
Naming Service 命名服务 命名服务将名称和对象进行关联,提供通过名称找到对象的操作。 例如:DNS系统将计算机名和IP地址进行关联。文件系统将文件名和文件句柄进行关联等等。
Name 名称 要在命名系统中查找对象,需要提供对象的名称。对象的名称是用来标识该对象的易于人理解的名称。 例如:文件系统用文件名来标识文件对象。DNS系统用机器名来表示IP地址。
Binding 绑定 一个名称和一个对象的关联称为一个绑定。 例如:文件系统中,文件名绑定到文件。DNS系统中,机器名绑定到IP地址。
Reference 引用 在一些命名服务系统中,系统并不是直接将对象存储在系统中,而是保持对象的引用。引用包含了如何访问实际对象的信息。
Context 上下文 一个上下文是一系列名称和对象的绑定的集合。一个上下文通常提供一个lookup操作来返回对象,也可能提供绑定,解除绑定,列举绑定名等操作。
创建JNDI
看一个模板
public static void main(String[] args) {
// 创建环境变量
Properties env = new Properties();
// JNDI初始化工厂类
env.put(Context.INITIAL_CONTEXT_FACTORY, "工厂类");
// JNDI提供服务的URL
env.put(Context.PROVIDER_URL, "url");
try {
// 创建JNDI服务对象
DirContext context = new InitialDirContext(env);
} catch (NamingException e) {
e.printStackTrace();
}
}
JNDI会自动搜索系统属性(System.getProperty())、applet 参数和应用程序资源文件(jndi.properties)。
Context.INITIAL_CONTEXT_FACTORY
是JNDI服务的具体名字,比如com.sun.jndi.dns.DnsContextFactory
是DNS服务对应的类名。具体服务对应的类名请自行在如图目录中寻找。
在com.sun.jndi.dns.DnsContextFactory中实现了InitialContextFactory,也就是说你可以通过实现javax.naming.spi.InitialContextFactory接口来创建自己的JNDI服务。javax.naming.spi.InitialContextFactory的结构如下。
public interface InitialContextFactory {
public Context getInitialContext(Hashtable<?,?> environment)
throws NamingException;
}
JNDI的动态协议转换
JNDI还有一个很重要的特点就是通过url的形式进行协议之间的转换,它可以在RMI、LDAP、CORBA等协议之间自动转换。例如
Context ctx = new InitialContext();
ctx.lookup("rmi://attacker-server/refObj");
//ctx.lookup("ldap://attacker-server/cn=bar,dc=test,dc=org");
//ctx.lookup("iiop://attacker-server/bar");
即使你使用了RMI的工厂类初始化的Context,当lookup时也会根据传入的url来转换协议。我们跟进lookup看下
public Object lookup(String name) throws NamingException {
return getURLOrDefaultInitCtx(name).lookup(name);
}
跟进getURLOrDefaultInitCtx
protected Context getURLOrDefaultInitCtx(String name)
throws NamingException {
if (NamingManager.hasInitialContextFactoryBuilder()) {
return getDefaultInitCtx();
}
String scheme = getURLScheme(name);
if (scheme != null) {
Context ctx = NamingManager.getURLContext(scheme, myProps);
if (ctx != null) {
return ctx;
}
}
return getDefaultInitCtx();
}
首先进行NamingManager.hasInitialContextFactoryBuilder()判断是否构建了初始化上下文工厂,跟进后发现返回空
然后进入getURLScheme获取协议
截取协议字符串,然后进入NamingManager.getURLContext(scheme, myProps)来初始化Context,最终跟进到jdk1.8.0_202/src.zip!/javax/naming/spi/NamingManager.java:592
在这里用协议名拼接了工厂类名,进而初始化了一个RMI的Context。
JNDI默认支持自动转换的协议有:
协议名称协议URLContext类DNS协议dns://com.sun.jndi.url.dns.dnsURLContextRMI协议rmi://com.sun.jndi.url.rmi.rmiURLContextLDAP协议ldap://com.sun.jndi.url.ldap.ldapURLContextLDAP协议ldaps://com.sun.jndi.url.ldaps.ldapsURLContextFactoryIIOP对象请求代理协议iiop://com.sun.jndi.url.iiop.iiopURLContextIIOP对象请求代理协议iiopname://com.sun.jndi.url.iiopname.iiopnameURLContextFactoryIIOP对象请求代理协议corbaname://com.sun.jndi.url.corbaname.corbanameURLContextFactoryJNDI和不同服务的配合使用
JNDI的存在其实是为了协同其他应用来进行远程服务,它可以在客户端和服务端中都进行一些工作,其目的是为了将应用统一管理。比如在RMI服务端中,JNDI可以进行bind、rebind等操作,在客户端上可以进行lookup、list等操作,这样可以不直接使用RMI的Registry的bind,加上JNDI的动态协议解析,从而方便统一管理各个应用。
JNDI DNS
使用DNS来做一个例子。
package com.longofo.jndi;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import java.util.Properties;
public class DNSClient {
public static void main(String[] args) {
// 创建环境变量
Properties env = new Properties();
// JNDI初始化工厂类
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
// JNDI提供服务的URL
env.put(Context.PROVIDER_URL, "dns://8.8.8.8");
try {
// 创建JNDI目录服务对象
DirContext context = new InitialDirContext(env);
// 获取DNS解析记录测试
Attributes attrs1 = context.getAttributes("baidu.com", new String[]{"A"});
Attributes attrs2 = context.getAttributes("qq.com", new String[]{"A"});
System.out.println(attrs1);
System.out.println(attrs2);
} catch (NamingException e) {
e.printStackTrace();
}
}
}
输出{a=A: 104.198.14.52}
,RMI和LDAP的大同小异。
JNDI RMI
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL,"rmi://localhost:9999");
Context ctx = new InitialContext(env);
//将名称refObj与一个对象绑定,这里底层也是调用的rmi的registry去绑定
ctx.bind("refObj", new RefObject());
//通过名称查找对象
ctx.lookup("refObj");
JNDI LDAP
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:1389");
DirContext ctx = new InitialDirContext(env);
//通过名称查找远程对象,假设远程服务器已经将一个远程对象与名称cn=foo,dc=test,dc=org绑定了
Object local_obj = ctx.lookup("cn=foo,dc=test,dc=org");
JNDI命名引用
Java使用序列化来传输对象数据,当序列化对象过大或者一些其他不适合序列化来传输的情况时,出现了命名引用传递。对象通过命名管理器解码以引用的方式间接存储在命名或目录服务中。
Reference reference = new Reference("MyClass","MyClass",FactoryURL);
ReferenceWrapper wrapper = new ReferenceWrapper(reference);
ctx.bind("Foo", wrapper);
这个地方有大坑,以后再说。
本文简单介绍了JNDI,下一篇文章将会具体讲解如何攻击JNDI。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。
Recommend
-
31
这是 代码审计知识星球 中Java安全的第六篇文章 上一篇我们详细说了如何利用codebase来加载远程类,在RMI服务端执行任意代码。那么,从原理上来讲,codebase究竟是如何传递进而被利用的呢?...
-
10
在写完 《Java中RMI、JNDI、LADP、JRMP、JMX、JMS那些事儿(上)》 的时候,又看到一个包含RMI-IIOP的
-
16
学习JNDI、RMI、JRMP 关于JNDI JNDI(Java Naming and Directory Interface)是Java提供的Java 命名和目录接口。通过调用JNDI的API应用程序可以定位资源和其他程序对象。JNDI是Java EE的重要部分,需要注意的是它并不只...
-
12
Java安全之RMI协议分析 0x00 前言 在前面其实有讲到过RMI,但是只是简单描述了一下RMI反序列化漏洞的利用。但是RMI底层的实现以及原理等方面并没有去涉及到,以及RMI的各种攻击方式。在其他师傅们的文章中发现RMI的攻...
-
7
2 min read攻击Java中的JNDI、RMI、LDAP(二)2020-04-03上文我简述了JNDI,本文我将演示如何攻击JNDI。JNDI注入这个东西是BlackHat 2016(USA)的一个议题
-
8
Twitter Don’t miss what’s happeningPeople on Twitter are the first to know.
-
2
Mocking out LDAP/JNDI in unit tests May 5, 2010 When unit testing a class that queries an LDAP server using Java's JNDI API I n...
-
2
最后一篇了吧(大概 前两篇介绍了RMI的流程和基础的攻击,这一篇写点进阶的东西 JEP290在JDK6u141、JDK7u131、JDK 8u121加入了JEP 290限制,JEP 290过滤策略有 进...
-
5
在第一篇的时候已经分析了RMI整个调用的流程,所以在这里就写一下攻击的流程 根据第一篇的分析 攻击服务端1.UnicastServerRef#dispatch -> UnicastServerRef#unmarshalValue->客户端攻击...
-
3
RMI介绍 RMI (Remote Method Invocation) 远程方法调用,顾名思义,它的功能就是就是实现调用远程方法 实现RMI的协议叫JRMP,RMI实现的过程中进行了java对象的传递,自然使用了序列化和反序列化,也自然产生了反序列化...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK