- 這幾天Log4j的問題消息滿天飛,今天我們就一起來看看從源碼角度看看這個漏洞是如何產生的。
- 大家都知道這次問題主要是由于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相關的,以及漏洞如何復現網上有一大把的教程,這里就不展開了。
- 關于漏洞的修復。
主要是通過設置noLookups變量的值,不讓它進去這個if里面的邏輯。
這個變量的值是來自下面這個屬性
所以在在代碼中加入System.setProperty("log4j2.formatMsgNoLookups","true");這句也就可以了。當然網上有更多其他的修復方法,這里就不討論了。
原文:https://www.cnblogs.com/wbo112/p/15690699.html