1. Log4j漏洞席卷全球
2021年11月中国软件工程师陈兆军发现了一个在Java服务中常用日志组件Log4j2的一个高危漏洞,并提交给官方。
2021年12月7日Apache发布 log4j-2.15-0-rc1版本,解决该漏洞。
2021年12月9日可能有人根据2.15.1版本复现出了漏洞利用方式,网上开始出现利用 Log4Shell 漏洞发起的攻击。
Log4j漏洞立刻席卷全球,CVE编号为CVE-2021-44228。
洛杉矶日报对此发文称:「互联网正在着火」「过去十年最严重的漏洞」「现代计算机历史上最大漏洞」「难以想到哪家公司不受影响」!
国内外多家媒体形容该 漏洞为——核弹级!!!
苹果Log4j漏洞(图片来自网络,如有侵权,请联系删除)
2. Log4j漏洞的原因
2.1 Log4j2介绍
如果说到漏洞的原因,就需要先介绍一下Log4j2这个框架。Log4j2 是一款 Java 日志记录框架。在Java开发中应用广泛。下面用最简单的描述给大家介绍一些 Log4j2 。
在 Java 项目中,当用户在输入一些信息或者系统需要记录一些状态用于后期排查问题,就会用到日志,比如在上面登录系统,就有可能在后台记录日志,如下图:
可以说 Log4j2 对于 Java 就像是飞机上的黑匣子。
2.2 lookup 功能介绍
一个日志记录功能怎么会引起这么大的漏洞呢,首先要提一些 Log4j2 中加入的 Lookup功能。Lookup 功能的本意是提供另外一种方式添加一些特殊值到日志中,以最大化松耦合地提供可配置属性供使用者以约定的格式进行调用。比如日期,只要按规定的格式输入,在日志里就会自动生成日期,不用再一个一个日志中写具体日期。
下面的代码中写的 Java 信息对应字段,日志中就会输出具体信息:
日志中输出的:
上面的日志示例可以看到,日志中打印的是 ${java:runtime} ,日志控制台输出的是Java(TM) SE Runtime Environment (build 1.8.0_131-b11) from Oracle Corporation。
在 org.apache.logging.log4j.core.pattern.MessagePatternConverter 中,会对每一条日志进行检验,如果包含 $ 和{,则触发替换机制,再根据约定的替换规则,将 ${ 后的信息进行替换。
详细的内置规则参见:Log4j2 中文文档 - Lookups | Docs4dev
在 Log4j2 内置的替换规则中,就包含 JNDI 这个容易引发漏洞的Java 规范。
2.3 JNDI
关于JNDI官方的说法是这样的:
Java命名和目录接口(Java Naming and Directory Interface,缩写JNDI),是Java的一个目录服务应用程序接口(API),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象 。
上面并不是很易懂,大家可以看下面的图。比如 Java Application 需要一些和项目解耦的资源,比如代码需要根据不同环境加载不同数据库,这时候不用把数据库的配置写死在自己的程序里,我可以通过 JNDI API, 只需要定义需要数据库配置信息的名字,具体的数据库信息可以由 JNDI SPI 提供,提供的方式可以是下面多种多样的方式。也就是说你的程序中只需要按照既定规则定义一个简单的名称,程序启动以后,看运行环境对应这个名称提供了什么,就把环境中提供的加载到项目中去。
在 javax.naming.spi.NamingManager 可以看到当项目中存在 JNDI 命名时,先从本地查找对应名称的类,如果本地没有就从远程加载对应名称的类(这也是这个漏洞的最主要原因 )
2.4 利用流程
根据上面的内容,我们总结下漏洞利用的流程。
3. Log4j漏洞的影响
影响面极广:由于Log4j是java最常用的日志记录框架,不只是我们在业务中,众多的开源组件也使用了Log4j框架,包括ElasticSearch、Logstash、Kafka、Apache Druid、Apache Struts2等等。所以影响极广。
利用简单:而从刚才的原因中我们可以看到,只需要构建JNDI注入就可以达到入侵的效果,这个入侵方式极为简单,即使是很多刚入门的脚本小子也能轻松入侵服务器。
入侵后权限:而且一旦入侵,很容易通过脚本获得最高权限,执行任意代码。
由于也就明白了为什么众多媒体把Log4j漏洞称为核弹级。
4. Log4j漏洞的解决方案
网上缓解的方案有很多,比如在spring中或者java中做一些配置,原理都是禁用JNDI。
但解决方案最彻底的还是升级最新版本,单对这个漏洞而言是一劳永逸的事情。
但是很多项目已经跑了很多年了,维护很困得,无法修改代码和依赖,这个时候就需要依赖比如WAF等设备,,过滤流量包中是有“${jndi:rmi”、 “${jndi:ldap”。