Log4j漏洞原始碼分析

wang03發表於2021-12-14

Log4j漏洞原始碼分析

  1. 這幾天Log4j的問題訊息滿天飛,今天我們就一起來看看從原始碼角度看看這個漏洞是如何產生的。

  2. 大家都知道這次問題主要是由於Log4j中提供的jndi的功能。

具體涉及到的入口類是log4j-core-xxx.jar中的org.apache.logging.log4j.core.lookup.StrSubstitutor這個類。

原因是Log4j提供了Lookups的能力(關於Lookups可以點這裡去看官方文件的介紹),簡單來說就是變數替換的能力。

在Log4j將要輸出的日誌拼接成字串之後,它會去判斷字串中是否包含${},如果包含了,就會當作變數交給org.apache.logging.log4j.core.lookup.StrSubstitutor這個類去處理。

相關的程式碼下面這個

首先是org.apache.logging.log4j.core.pattern.MessagePatternConverter這個類的format方法

圖中標註1的地方就是現在漏洞修復的地方,讓noLookups這個變數為true,就不會進去裡面的邏輯,也就沒有這個問題了。

圖中標註2的地方就是判斷字串中是否包含${,如果包含,就將從這個字元開始一直到字串結束,交給圖中標註3的地方去進行替換。

圖中標註3的地方就是具體執行替換的地方,其中config.getStrSubstitutor()就是我們上面提到的org.apache.logging.log4j.core.lookup.StrSubstitutor

StrSubstitutor中,首先將${}之間的內容提取出來,交給resolveVariable這個方法來處理。

我們看下resolver的內容,它是org.apache.logging.log4j.core.lookup.Interpolator類的物件。

它的lookups定義了10中處理型別,還有一個預設的defaultLoopup,一種11中。如果能匹配到10中處理型別,就交給它們去處理,其他的都會交給defaultLookup去處理。

匹配規則也很簡單,下面簡單舉個例子。

1.如果我們的日誌內容中有${jndi:rmi://127.0.0.1:1099/hello}這些內容,去掉${},傳遞給resolver的就是jndi:rmi://127.0.0.1:1099/hello

2.resolver會將第一個:之前的內容和lookups做匹配,我們這裡獲取到的是jndi,就會將剩餘部分jndi:rmi://127.0.0.1:1099/hello交給jdni的處理器JndiLookup去處理。

圖中標註1的地方入參就是jndi:rmi://127.0.0.1:1099/hello

圖中標註2的地方就是jndi

圖中標註3的地方就是rmi://127.0.0.1:1099/hello

圖中標註4的地方就是處理器JndiLookup類的物件

圖中標註5的地方就是jndi來處理的入口

關於jndi相關的,以及漏洞如何復現網上有一大把的教程,這裡就不展開了。


  1. 關於漏洞的修復。

主要是通過設定noLookups變數的值,不讓它進去這個if裡面的邏輯。

這個變數的值是來自下面這個屬性

所以在在程式碼中加入System.setProperty("log4j2.formatMsgNoLookups","true");這句也就可以了。當然網上有更多其他的修復方法,這裡就不討論了。

相關文章