最近,互联网技术圈中最热门的是log4j2的漏洞。在同一时间,出现了各种分析文章,漏洞的版本,漏洞的原因,漏洞的修复以及程序员的加班时间。
经常阅读我的文章的朋友知道,面对如此流行而有趣的技术要点,我们怎么能错过 - 深度分析?您可能听说过漏洞的“罪魁祸首”是jndi,我们会谈论它今天。
jndi,如此熟悉,但是...熟悉的陌生人?jndi是什么?好吧,如果您有一年的编程经验,但是您不知道Jndi甚至听说过。本文很快。
说到JNDI,应该使用从事Java EE编程的人,但是您知道您正在使用它,然后取决于您对技术的研究深度。这次的Log4J2暴露了漏洞,错误地表明了很多数量项目中直接或间接使用JNDI。让人看到Jndi是什么鬼?
让我们看一下Sun的官方解释:
Java命名和目录接口(Java命名和目录接口(JNDI)是一组API,用于从Java应用程序访问名称和目录服务。名称服务即将与对象关联,以便通过相应的名称访问这些对象。目录服务是具有属性和名称的对象的命名服务。
命名或目录服务允许您集中管理共享信息的存储,这在网络应用程序中很重要,因为它可以使此类应用程序更加一致且易于管理。所有与打印机相关的应用都可以使用。
这个概念很抽象吗?阅读几次后我听不懂吗?一张照片赢得了数千个单词:
您是什么意思是注册中心?是的,如果您使用了NACOS或阅读NACOS的源代码,则必须熟悉命名服务的概念。在JNDI中,尽管实现方法是不同的,并且应用程序方案是不同的,但确实如此不会通过模拟注册中心影响您对JNDI的理解。
如果您说尚未使用NACOS,那就可以了,地图始终使用。查找或搜索,例如地图获取方法。
简而言之,JNDI是一个规范,规范需要相应的API(即某些Java类)才能实现。通过此组API,对象可以与名称关联,同时,它提供了一种方法根据名称找到对象。
最后,对于JNDI,Sun Company仅提供接口规范,该规范由相应的服务器实施。例如,Tomcat具有Tomcat的实现,JBOSS具有JBOSS的实现,只是遵守规范。
上面提到了命名服务,类似于MAP绑定和搜索功能。例如:Internet中的域命名服务(DNS)是为IP地址提供域名的命名服务。在浏览器中输入域名,通过DNS查找相应的IP地址,然后访问网站。
目录服务是命名服务的扩展。这是一项特殊的命名服务,提供相关性和搜索属性和对象。目录服务通常具有命名服务(但是命名服务不必具有目录服务)。例如,电话簿是典型目录服务。通常,首先在电话簿中找到相关人员的名字,然后找到此人的电话号码。
目录服务允许属性(例如用户电子邮件地址)与对象关联(而不是命名服务)。这样,当使用目录服务时,您可以根据对象的属性搜索它们。
JNDI通常分为三层:
总体体系结构分层如下所示:
应该注意的是:JNDI还提供应用程序编程接口(API)和服务提供商界面(SPI)。
对于与命名或目录服务互动的应用程序,必须有一个服务提供商的JNDI服务提供商,这是JNDI SPI扮演角色的阶段。
服务提供商基本上是一组类,它实现了针对特定命名和目录服务的各种JNDI接口 - 这与针对特定数据系统实现各种JDBC接口的JDBC驱动程序非常相似。作为开发人员,您不会需要担心JNDI SPI。确保为使用的每个名称或目录服务提供服务程序。
让我们看一下JNDI容器的概念和应用程序方案。
JNDI容器环境中的命名(命名)正在以某个名称的形式绑定Java对象,以与容器环境结合。使用时,请调用容器环境的搜索方法。
容器环境本身也是一个Java对象,它也可以通过一个名称绑定到另一个容器环境。将一个上下文对象绑定到另一个上下文对象,形成父级 - 孩子 - 级别的关系。多个上下文对象最终可以对联成为树状的结构。树中的每个上下文对象都可以是绑定的Java对象。
JNDI使用JNDI的基本用途是首先创建一个对象,然后将其放在容器环境中,然后在使用时将其取出。
目前,您是否想知道,为什么这么艰难?换句话说,它会带来什么好处?
在实际应用中,系统或框架程序通常将资源对象绑定到JNDI环境中。在系统或框架中运行的模块程序可以从JNDI环境中找到。
JDNI和我们的实践的一个示例是使用JDBC。当它不是基于JNDI实施时,通常需要连接数据库:加载数据库驱动程序,连接数据库,操作数据库和关闭数据库。Different数据库中的实现中有不同在上述步骤中,参数可能会更改。
如果这些问题是由J2EE容器配置和管理的,则该程序只需要引用这些配置和管理。
以Tomcat服务器为例,启动时,您可以创建连接到某个数据库系统的数据源对象并将数据源对象绑定到JNDI环境中。Servlet和JSP程序可以从JNDI环境查询此数据源对象不用关心如何创建数据源对象。
这种方法大大增强了系统的维护。即使Bento数据库系统的连接参数更改,也与应用程序开发人员无关。JNDI将一些关键信息放入内存中,这可以提高访问效率。通过JNDI,它可以实现解耦的目的,并使系统更可维护和可扩展性。
有了上述概念和基本知识,我们可以立即开始实际战斗。
在架构图中,JNDI的实现层包含各种实现方法。在这里,RMI实施是为了撰写实例来体验一个实施。
RMI是Java中的远程方法调用,该调用基于Java序列化和衍生物。
您可以通过以下代码构建RMI服务:
上面的代码首先定义了RMiservice接口,该接口实现远程并实现了RMIService接口。在实现过程中,UnicastremoteObject的特定服务实现类。
最后,通过RMISERVER中的注册表收听端口1099,并绑定RMIService接口的实现类。
下面构建客户端访问:
其中,分别提供了两个参数,分别代表上下文的初始化和服务的URL。
执行上述过程,您可以获取远程端的对象并调用它,以便实现RMI通信。当然,服务器和客户端在同一台计算机中使用,该机器使用“ Localhost”。如果是远程服务器,请用相应的IP替换它。
通常,如果您想构建攻击,则只需要伪造服务器端并返回恶意序列化有效载荷即可。接收后,触发客户端以触发衍生产品。但实际上,对返回的类型有一定的限制。
在JNDI中,有一种更好的使用方法,涉及命名参考的概念。
如果某些本地实例类太大,您可以选择一个远程引用,并通过远程调用引用远程类,这就是JNDI对有效负载的使用也将涉及HTTP服务的原因。
RMI服务只会返回名称参考,告诉JNDI如何找到此类,然后该应用程序将在HTTP服务下找到类文件并加载。这次,只要恶意代码写入静态方法,将其加载后将执行。
基本过程如下:
修改rmiserver的代码实现:
由于较高的Java版本,系统变量com.sun.jndi.rmi.object.trusturlcodebase首先设置为true。
结合参考涉及三个变量:
目前,通过Python启动简单的HTTP监视服务:
打印日志表示端口8000处的HTTP监视。
相应的客户端代码修改如下:
高管客户代码发现,Python的服务听取了该服务的收听如下:
可以看出,客户端已远程加载恶意类(Calc.Class)文件,但是Python服务未返回相应的结果。
以上代码证明它可以以RMI的形式攻击。以下是基于上述代码和Spring Boot Web服务的形式。通过JNDI注入+RMI调用本地计算器。
上述基本代码不变,并且将来只能对rmiclient类进行良好的态度,并且同时添加了一些新的类和方法。
步骤1:建立攻击课
创建一个攻击 - 类错误的bugfinder来启动本地计算器:
我是Mac操作系统。该代码基于MAC命令实现方法。通过Java命令来调用calculator.app。在同一时间,当类初始化类时,执行了启动计算器的命令。
编译上述代码并将其存储在一个位置中。在这里,将副本分开并放置在“/users/zzs/temp/bugfinder.class”路径中。
步骤2:构建Web服务器
使用RMI调用时,Web Service返回攻击文件。此处采用了Spring Boot项目。核心实施代码如下:
在Web服务中,bugfinder.class文件已读取并返回到RMI服务。COOCUS提供可以返回可执行类文件的Web服务时。
步骤3:修改rmiserver
修改rmiserver的结合:
参考参数此处是攻击类和远程下载的网址。
步骤4:执行客户端代码
执行客户端代码以访问:
打开本地计算器:
基本攻击模式如上所述。基于上述模式,让我们看一下log4j2的漏洞。
Spring Boot项目中受影响版本的Log4J2的简介:
在这里应注意的是,消除了弹簧启动的默认日志,否则可能不会复制该错误。
修改RMI的服务器代码:
直接访问Bugfinder,JNDI绑定到:Hello。
客户端介绍Log4J2的API,然后记录日志:
日志中记录的信息为“ $ {jndi:rmi://127.0.0.0.1:1099/hello}”,这是RMI服务器的地址和绑定的名称。
执行程序并发现计算器已成功打开。
当然,在实际应用中,可以通过参数获得记录的日志信息,例如在Spring Boot中定义以下代码:以下代码:
在浏览器中,请求URL是:
用户名参数的值为“ $ {jndi:rmi://127.0.0.1:1099/hello}”“ urlencoder#encode.at eccode.at at这次,访问URL地址也可以打开计算器。
至于log4j2内部逻辑漏洞触发了jndi调用部分,它将不再扩展。有兴趣的朋友可以在上面的示例中看到完整的呼叫链接。
通过分析Log4J2漏洞,本文不仅向您展示了JNDI的基本知识,而且还完美地重现了基于JNDI的工具。本文所涉及的代码已亲自对其进行了实验。强烈建议您还运行代码,以真正感觉如何实现攻击逻辑。
JNDI注射事件不仅发生在log4j2中,而且还出现在许多其他框架中。尽管JDNI给我们带来了便利,它也带来了风险。在示例中,您还会看到,在高版本的JDK中,没有特殊设置(com.sun.jndi.rmi.object.trusturlcodebase设置为true),或者无法触发漏洞。这更令人放心。
此外,如果这种脆弱性真正出现在您的系统中,则强烈建议立即修复它。在没有报告这种脆弱性之前,只有少数人会知道。一旦每个人都知道,许多人都渴望尝试,所以快点保护它。
博客作者简介:“ Springboot Technology Inner Book”技术书籍作者,喜欢学习技术,撰写技术干货文章。
公共帐户:博客作者的公共帐户“计划的新愿景”,欢迎关注?
技术交流:请联系博客微信:Zhuan2quan