当前位置:首页 > 时尚

怎么检测服务器是否有log4j漏洞

2021年12月9日深夜,检测Apache Log4j 2 被曝出远程代码执行漏洞(CVE-2021-44228)。服务那个周末,器否全球运维圈几乎没人睡觉。检测我认识的服务一个安全工程师连熬两宿,就为了扫完公司三百多台服务器。器否他后来跟我说,检测最怕的服务不是找到漏洞,是器否不知道哪台机器藏着 Log4j 却没人记得。

Log4j 是检测 Java 生态里最常用的日志组件之一。很多项目把它当空气——用了但没感觉。服务问题就出在这:你可能根本没在代码里直接写过 import org.apache.logging.log4j,器否但你的检测 Spring Boot 项目、Kafka 客户端、服务甚至某些中间件,器否早就把它打包进去了。所以检测这件事,不能只翻自己的代码。

先搞清楚哪些版本有问题

Log4j 2.x 系列,2.0-beta9 到 2.14.1 全部受影响。2.15.0 修了一版但没修干净,2.16.0 才算真正堵住。2.17.0 又补了 DoS 相关的坑。如果你看到 log4j-core-2.14.1.jar 这种文件名,基本可以确定中招。1.x 版本不受这个漏洞影响,但 1.x 早就停止维护了,另说。

方法一:直接搜 jar 包

最土也最可靠的办法。登录服务器,找到 Java 应用的 classpath 或者部署目录,搜 log4j-core 这个关键字。Linux 下一条命令:

find / -name "log4j-core*.jar" 2>/dev/null

如果输出里有 2.0 到 2.14.1 之间的版本,这台机器就有风险。注意别只搜应用目录,有些老项目把依赖散落在 /opt、/usr/share/java 甚至用户 home 目录下。我见过一个案例,某台机器上跑着三个 Java 服务,运维只检查了主服务,结果一个边缘的定时任务里藏着 2.13.0 的 log4j-core,最后被挖矿程序盯上了。

方法二:检查进程实际加载的 jar

光看文件系统不够,因为同一个 jar 可能有好几个版本,进程到底加载了哪个才是关键。用 lsof 或者 jcmd 看:

lsof -p <PID> | grep log4j

或者更直接:

jcmd <PID> VM.system_properties | grep java.class.path

拿到 classpath 后,逐个确认 log4j-core 的版本。这个方法比盲搜文件准得多,但需要你知道 Java 进程的 PID。生产环境里进程多,建议写个脚本批量跑。

方法三:用扫描工具

手动查太慢。当时社区出了不少工具,比如 log4j-scan、log4j-detector。我个人用过 log4j-detector,它是一个 jar 包,跑起来直接扫目录,输出哪些文件里嵌了有漏洞的 Log4j。适合离线环境批量排查。商业扫描器像 Nessus、Qualys 后来也加了检测插件,但更新速度参差不齐,别完全依赖。

还有一个取巧的办法:用 nmap 的 http-log4j2 脚本对暴露在外的 HTTP 服务发探测请求。但这只对能触发 JNDI 注入的接口有效,内网服务或者非 HTTP 协议根本扫不到。别把它当唯一手段。

方法四:看日志里有没有异常 payload

已经被人打过但没打成功的机器,日志里会留下痕迹。搜 ${ jndi: 这个关键字:

grep -r "\${ jndi:" /var/log/ 2>/dev/null

如果日志里出现 ${ jndi:ldap://... 这种字符串,说明有人尝试利用过。注意,Log4j 会把 payload 当普通字符串写进日志,所以这个特征很明显。但反过来,没搜到不代表没漏洞——攻击者可能还没来,或者用了不写日志的利用方式。

几个容易漏掉的角落

容器镜像。很多人只扫了运行中的服务器,忘了 CI/CD 流水线里构建的镜像。一个基础镜像里带了有漏洞的 Log4j,后面所有基于它的服务全中招。用 trivy 或者 grype 扫镜像层,比进容器里手动找快得多。

还有 fat jar。Spring Boot 打出来的可执行 jar,依赖全打包在里面。你不能直接 find 到 log4j-core-2.14.1.jar,因为它被嵌套在 BOOT-INF/lib/ 下面。得用 unzip -l 或者 jar tf 看内部结构。

最后说个真实教训。某公司安全团队扫完所有服务器,报告说“无漏洞”。结果两周后一台机器被入侵,原因是那台机器上的 Java 应用用了 Log4j 2.14.1,但 jar 包被重命名成了 core.jar,文件名扫描直接跳过。所以检测逻辑不能只看文件名,得看 jar 内部的 META-INF/MANIFEST.MF 或者 class 文件里的版本字符串。

检测不是一次性的活。Log4j 漏洞之后,各种 Java 组件漏洞一个接一个。建立一份准确的资产清单,比每次出事再临时抱佛脚强得多。

分享到: