原创作者:逸尘 最全的 Apache Log4j2 远程代码执行漏洞 研究分析文章

0x01漏洞前言

Apache Log4j2 是一个开源的 Java 日志框架,被广泛地应用在中间件、开发框架与 Web 应用中, Apache Log4j2 组件存在远程代码执行漏洞,该漏洞是由于 Apache Log4j2 某些功能存在递归解析功能,未经身份验证的攻击者通过发送特定恶意数据包,可在目标服务器上执行任意代码。

漏洞编号:

CVE-2021-44228

漏洞标签:

影响范围广,工具/武器化成熟、历史重大漏洞、红队打点必备、服务器权限、漏洞价值大、供应链风险

0x02 漏洞影响

影响范围: Apache Log4j 2.x<=2.14.1 / Apache Log4j2 2.15.0-rc1 **注:**使用Apache Log4j 1.X版本的应用,若开发者对JMS Appender利用不当,可对应用产生潜在的安全影响。

供应链影响范围:

Spring Boot 是一个基于Spring框架,用于开发Web应用和微服务的开源框架。

Apache Struts2 是一个基于MVC架构的Java Web应用框架,用于构建企业级Java Web应用程序。

Apache Solr 是一个基于Lucene的搜索平台,用于帮助用户快速地进行全文搜索及相关性查询。

Apache Flink 是一个基于流处理的分布式计算框架,用于高效地处理数据流和批数据,并支持丰富的流处理API。

Apache Druid 是一种用于实时查询和分析流式和批量数据的高性能、分布式的列存储数据库。

ElasticSearch 是一个基于Lucene的分布式搜索和分析引擎,被广泛应用于大规模数据搜索和企业级日志分析。

Apache Flume 是一种可靠、分布式的、高可扩展性的日志存储和聚合系统。

Dubbo 是一个高性能、轻量级的分布式服务框架,提供了基于RPC调用的远程服务调用功能。

Redis 是一种开源的高性能、非关系型的内存数据存储系统,广泛应用于缓存和会话管理等场景。

Logstash 是一种流处理工具,可用于将数据从不同来源采集、转换和传输到不同的存储后端。

Kafka 是一个高吞吐量、低延迟的分布式消息系统,可用于构建高性能、可伸缩的数据流处理应用。

VMware 是一种虚拟化软件,被广泛应用于构建和管理虚拟机和云计算基础设施。

https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core/usages?p=1

此漏洞影响广泛,开源组件中有近两万项目使用该存在漏洞的模块,绝对是目前为止影响最为广泛的漏洞。

Apache Log4j 2.15.0-rc2(与官网的2.15.0稳定版相同)

Apache Log4j 2.15.1-rc1

0x03 漏洞原理分析

漏洞的核心主要是在内容中一旦发现日志中包含 ${} 就会将表达式的内容替换为表达式解析后的内容,而不是表达式本身,从而导致攻击者构造符合要求的表达式供系统执行。 在Log4j2中提供了变量占位符,使用${}包围变量名,可以在日志记录中输出上下文信息。在运行时,这些占位符会被替换为相应的值。

以下是每个占位符的简要说明:

${ctx:loginId} 从 ThreadContext 中获取名为 loginId 的值。

${map:type} 从 ThreadContext 中的 map 中获取名为 type 的值。

${filename} 记录当前日志的源文件名。

${date:MM-dd-yyyy} 记录当前日期,格式为 月-日-年 。

${docker:containerId} 记录当前应用程序运行的 Docker 容器 ID。

${env:USER} 记录当前用户的用户名。

${event:Marker} 获取事件中与给定标记关联的信息。

${mdc:UserId} 从 MDC(Mapped Diagnostic Context)中获取名为 UserId 的值。

${java:runtime} 记录当前 Java 运行时的版本号。

${java:vm} 记录 Java 虚拟机的名称。

${java:os} 记录操作系统的名称。

${jndi:logging/context-name} 获取 JNDI 上下文中名为 logging/context-name 的值。

${hostName} 记录当前主机名。

${k8s:*} 记录 Kubernetes 环境中有关应用程序当前运行上下文(如容器名称,命名空间名称等)

${log4j:configLocation} 记录 Log4j2 配置文件的位置。

${marker:name} 获取携带给定名称的标记的信息。

${spring:*} 记录 Spring 应用程序中相关信息的值,如应用程序名称。

${main:*} 记录启动日志中使用的命令行参数。

${name} 如果可用,记录当前日志记录器的名称。

${marker} 如果可用,记录当前事件中指定的标记。

${sys:logPath} 从系统的环境变量中获取名为 logPath 的值。

${web:rootDir} 记录 Web 应用程序根目录的名称。

漏洞分析总结

在构造语句执行时,log4j日框架志在打印日志,当遇到 ${

后,“Interpolator 类”以 : 号作为分割,将表达式内容分割成两部分,这里的**Interpolator 类(**是一个字符串替换工具,它可以在字符串中查找特定的关键字并将其替换为指定的值),而在前面部分作为 前缀(prefix),后面部分作为 键(key),然后通过前缀去lookup查找找对应的实例,调用 lookup 方法,最后将 key 作为参数带入执行。

当开发者想在日志中打印今天的日期,则只需要输出${data:MM-dd-yyyy}

此时log4j会将${}中包裹的内容单独处理,将它识别为日期查找,然后将该表达式替换为今天的日期内容输出为“08-22-2022”

这样做就不需要开发者自己去编写查找日期的代码,这样极大的方便了开发者。

${}除了支持日期,还支持输出系统环境变量等功能,其实打印日期,打印系统变量这种对系统而言构不成什么威胁,最主要的原因是log4j还支持JNDI协议。JNDI它会提供一个目录系统,将服务名称与对象关联起来,类似于输入name 调用对象。调用使用的

好文阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。