昨晚推特上一条博文引起了圈内的大量关注
夭寿啦!log4j 2.17.0 可以RCE 啦!!
然鹅:
嘘……
圈内人士嘘声一片……
修改配置文件 RCE??就这就这???
那么修改配置文件来RCE到底是怎么“流行”起来的呢?
这件事还要从 Log4j 2 的 RCE 说起
在log4j2 的 GitHub项目有个 Pull:
https://github.com/apache/logging-log4j2/pull/608
一位叫“TopStreamsNet”的老外提到:
如果您查看 jndi 在 1.x 中的工作方式,您会发现有两个地方可以完成查找 - 即 JMSAppender.java:207 和 JMSAppender.java:222 - 如果您将 TopicBindingName 或 TopicConnectionFactoryBindingName 设置为 JNDI 可以处理的内容 - 例如“ldap://host:port/a”JNDI 将做与 2.x 完全相同的事情 - 所以 1.x 是易受攻击的,只是攻击向量“更安全”,因为它取决于配置而不是用户 输入
然后通过配置文件 RCE 的这件事就开始讨论起来了
特别是 Log4j2 的作者回复到:
如果攻击者可以修改某个系统 S 上的配置文件,那么可以假设 S 已经被很大程度地渗透了。
如果攻击者可以修改 log4j.properties (log4j 1.x),她就不需要下载恶意代码,她可以轻松地将恶意类文件放在类路径中并让它们执行。
因此,在非常严格的意义上,log4j 1.x 中存在漏洞,但与日志参数引起的 RCE 没有任何关系。
实际上可以看得出来,Log4j2 的作者一开始并不认同这个老外的观点,但有意思的来了
就在大家认为这个“漏洞”不是漏洞的时候,RadHat 出来作妖了:
https://access.redhat.com/security/cve/CVE-2021-4104
他们把这个由配置文件引起的 RCE 定义为漏洞,并且给了cvss v3 7.5的中危评分!
然后有人又在 log4j2 那个 pull 下面回复了:
路人:看,你看,RedHat 发了一个 CVE,而且还是7.5的评分!(实际上一开始给了 8.0)
当然,也有人回复到:
路人:TMD,ReaHat 你不懂规矩,不讲武德,人家 log4j 官方都没发话呢,你出来搞什么事情
后来迫于压力下,log4j 认了这个 CVE
我们决定保留 Red Hat 分配的 CVE,以节省创建另一个并拒绝他们的 CVE。
log4j 官方:行了行了,我认,我认还不行吗
至此,由log4j 在 pull 上讨论出的第一个 由配置文件引发 RCE的 CVE 被 RedHat折腾出来了
在log4j1 这个 CVE 发布前,实际上我就对“TopStreamsNet”这位老外提出的看法进行了研究:
log4j 1.x 与 logback 的鸡肋RCE讨论:
https://www.cnpanda.net/sec/1131.html
并且我发现实际上log4j 1.x 的配置文件 RCE 并不能立刻生效,因为修改 log4j 1.x 的配置文件需要重新加载后才可以生效,在生产环境下谁闲着没事主动重启或者重新加载配置文件?
但 logback 不太一样,因为 logback 有个 scan 属性,可以自动扫描配置文件是否发生了改变,如果发生了改变,那么就会自动更新配置文件。所以研究的时候写了一个 SpringBoot 的演示Demo 发到了 GitHub 上。
凑巧的是,在 logback 的官方 issue 上看到一个提问,大意是 logback 中是否存在RedHat 发布的那个漏洞,然后我回复了之前那个SpringBoot 演示 Demo 的地址,后来 logback的作者也给分配了CVE-2021-42550,还发邮件问我要不要 credit
老外还是热心的,但是我觉得这漏洞本身限制很大很鸡肋,而且 @香依香偎 师傅在一年前就提出了这个利用方式:
所以我拒绝了credit。
后来通过 @TiGer 师傅得知这个 logback 漏洞实际上出现过实际例子的利用:
可以参考:https://www.cnblogs.com/zpchcbd/p/15542705.html
回过头来看看这个log4j 2.17.0 的配置文件 RCE,确实有点离谱,因为修改完配置文件后,它不像 logback 一样可以实时生效,属于鸡肋中的鸡肋了。
实际上 @pwntester 大神也说了:
大多数使用数据库的 Java 应用程序都有配置文件,您可以在其中指定 JNDI 地址以获取 JDBC 数据源
简单搜索发现,可以通过 JNDI设置配置文件的部分应用如下:
Apache ODE
https://ode.apache.org/using-a-jndi-datasource-under-servicemix-jbi.html
Apache Shrio
https://shiro.apache.org/static/1.3.2/apidocs/org/apache/shiro/jndi/JndiTemplate.html
https://www.programmerall.com/article/1371213168/
Tomcat
https://tomcat.apache.org/tomcat-8.0-doc/jndi-datasource-examples-howto.html
TomEE
https://tomee.apache.org/jndi-names.html
SpringBoot
https://blog.roncoo.com/article/133919
等等等
太多太多了,实际上正如@pwntester说的那样,JNDI 类似于在一个中心注册一个东西,以后要用的时候,只需要根据名字去注册中心查找,注册中心返回你要的东西。比如在 web应用中,我们可以将一些东西(最常用的就是数据库相关的配置信息)交给服务器软件去配置和管理,在程序代码或者配置文件中只要通过名称查找就能得到我们注册的东西,而且如果注册的东西有变,比如更换了数据库,我们只需要修改注册信息,名称不改,因此代码也不需要修改。
这是SUN公司提供的一种标准的Java命名系统接口,是一种特性,因此一般来说,只要存在 JNDI 的地方,都能够利用 ldap 协议去实现 RCE,当然,不仅仅是 ldap 协议,实际上还有很多可用的协议:
总之,我认为log4j 2.17.0这个 CVE,分配了就算了,但过分的是,这老外还好意思发表在推特上来说log4j 2.17.0又出 RCE 漏洞(刷洞就刷洞,还吆喝一嗓子,结果还是这漏洞,不是让别人像吃了屎一样难受吗)
一句话总结:通过配置文件来实现 RCE,只能说是一种攻击手段,而不能说是一种常规漏洞。