近年來,我們對(duì)序列化攻擊產(chǎn)生了濃厚的興趣。就在幾個(gè)月前,我們決定投入一點(diǎn)精力研究Apache Dubbo。據(jù)我們所知,Dubbo以多種方式對(duì)許多程序進(jìn)行了反序列化處理。自Apache基金會(huì)使用Dubbo后,Dubbo在世界各地的用戶數(shù)量顯著增加。
據(jù)2019年中期新聞稿報(bào)道,中國有十幾家企業(yè)已經(jīng)開始使用Dubbo,其中包括阿里巴巴集團(tuán)、中國人壽、中國電信、當(dāng)當(dāng)網(wǎng)、滴滴出行、海爾和中國工商銀行等。該報(bào)道指出,Apache宣布將Dubbo提升為Apache頂級(jí)項(xiàng)目。
圖2 – Dubbo用戶(圖片來源于Apache Dubbo官網(wǎng))
我發(fā)現(xiàn)Apache Dubbo提供商和用戶使用的版本≤Dubbo 2.7.3,當(dāng)配置可接受HTTP協(xié)議時(shí),允許遠(yuǎn)程攻擊者向暴露的服務(wù)發(fā)送惡意程序,從而導(dǎo)致遠(yuǎn)程代碼執(zhí)行的問題。這是在未經(jīng)認(rèn)證的情況下發(fā)生的,攻擊者只需知道很少的信息就可以利用此漏洞做文章。具體來說,如果HTTP啟用,在任何Dubbo實(shí)例上,攻擊者只需要利用此處所述的漏洞和一個(gè)URL就能順利攻破服務(wù)系統(tǒng)。本報(bào)告附有概念驗(yàn)證視頻。
攻擊者可以利用此漏洞破解Dubbo提供商的服務(wù)(該服務(wù)旨在從其消費(fèi)者獲得遠(yuǎn)程連接)。然后攻擊者可以用一個(gè)惡意的Dubbo提供商程序?qū)F(xiàn)有Dubbo提供商程序替換掉。接下來,該替換程序可使用類似的惡意對(duì)象對(duì)消費(fèi)者作出響應(yīng),從而激活遠(yuǎn)程代碼執(zhí)行程序,讓攻擊者攻破整個(gè)Dubbo集群。
造成這種漏洞問題的根本原因在于Spring框架中使用了遠(yuǎn)程反序列化服務(wù)。Spring框架文檔明確建議,用戶切勿使用不可信的數(shù)據(jù)運(yùn)用Spring框架。再加上庫(該庫含一個(gè)鮮為人知的小工具鏈)過時(shí)的問題,導(dǎo)致遠(yuǎn)程代碼執(zhí)行的問題產(chǎn)生。不可信數(shù)據(jù)反序列化處理的不安全隱患,加上小工具鏈的存在,造成遠(yuǎn)程訪問和遠(yuǎn)程未經(jīng)認(rèn)證的代碼執(zhí)行無縫對(duì)接的隱患產(chǎn)生。
Chris Frohoff和Moritz Bechler的研究和工具(ysoserial和marshalsec)功不可沒。他們將一些代碼用在小工具鏈上,他們的研究為解決這種漏洞問題奠定了基礎(chǔ)。
嚴(yán)重級(jí)別
Checkmarx認(rèn)為該漏洞的CVS評(píng)分為9.8(嚴(yán)重),因?yàn)樗且粋€(gè)未經(jīng)認(rèn)證的遠(yuǎn)程代碼執(zhí)行漏洞,在Dubbo服務(wù)的權(quán)限級(jí)別提供特權(quán),從而完全破解了該服務(wù)的機(jī)密性、完整性和可及性。
雖然并非所有Dubbo實(shí)例都配置使用HTTP協(xié)議,但就配置使用該協(xié)議的Dubbo版本(帶有已知漏洞)而言,只要提供很少且隨時(shí)可用的信息(即存在漏洞的服務(wù)URL),這類系統(tǒng)就非常容易受到攻擊。任何人只要通過注冊(cè)表(如Zookeeper)等服務(wù)就可以在網(wǎng)上獲得上述服務(wù)URL,且該服務(wù)URL不被視為秘密或機(jī)密內(nèi)容。
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F/RL:U/RC:C/CR:H/IR:H/AR:H
規(guī)范
這是怎么回事?
激活遠(yuǎn)程HTTP協(xié)議的Dubbo應(yīng)用程序會(huì)產(chǎn)生反序列化的不安全問題。如果Apache Dubbo提供商實(shí)例啟用了HTTP,攻擊者就可以通過提交一個(gè)帶有Java對(duì)象的POST請(qǐng)求,完全破解該實(shí)例。
Dubbo HTTP實(shí)例試圖在Java ObjectStream中對(duì)數(shù)據(jù)進(jìn)行反序列化處理,而Java ObjectStream包含一組惡意的類(常被稱為小工具鏈),調(diào)用該工具鏈會(huì)導(dǎo)致系統(tǒng)執(zhí)行惡意代碼。在這種情況下,有問題的惡意代碼允許攻擊者對(duì)系統(tǒng)命令進(jìn)行任意操作。異常創(chuàng)建期間,在這個(gè)小工具鏈上的Dubbo實(shí)例中進(jìn)行內(nèi)部toString調(diào)用時(shí),小工具鏈就會(huì)被調(diào)用。
重建問題
攻擊者可以將帶有惡意對(duì)象的POST請(qǐng)求提交到Apache Dubbo HTTP服務(wù)的bean URL,以便執(zhí)行遠(yuǎn)程代碼。在這種情況下,bean是由Spring綁定到指定Dubbo協(xié)議端點(diǎn)的接口實(shí)現(xiàn)類。該bean連接到一個(gè)URL,該bean的請(qǐng)求體包含一個(gè)HTTP遠(yuǎn)程調(diào)用,用于確定適合的bean調(diào)用方法和參數(shù)的選用。
攻擊者獲得bean的URL之后,他們只需要通過標(biāo)準(zhǔn)POST請(qǐng)求提交一個(gè)惡意的小工具鏈即可利用這個(gè)漏洞做文章。
如果HTTP服務(wù)和協(xié)議已經(jīng)啟用,在具有Dubbo-Remoting-HTTP的vanilla Apache Dubbo范圍內(nèi)能夠找到允許執(zhí)行遠(yuǎn)程操作系統(tǒng)命令的新小工具鏈。
為概念驗(yàn)證(PoC)重建受損Dubbo HTTP實(shí)例
遵守以下指南:
鎖定易受攻擊的實(shí)例
要觸發(fā)此漏洞,攻擊者必須識(shí)別一個(gè)指向Dubbo HTTP bean的URL。URL地址信息通常是公開或無需特權(quán)訪問即可獲得的,只要攻擊者通過Zookeeper等Dubbo服務(wù)注冊(cè)表以及多播就可以在網(wǎng)上獲得該URL地址,無須部署良好的HTTPS傳遞途徑,從而實(shí)現(xiàn)中間人攻擊。
觸發(fā)漏洞概念驗(yàn)證
有關(guān)運(yùn)行的概念驗(yàn)證代碼,參加附件1。請(qǐng)注意,Dubbo實(shí)例的IP地址等變量需要在這段代碼中進(jìn)行修改。
如上所述,攻擊者需要與Dubbo HTTP服務(wù)相同的依賴項(xiàng)。在此概念驗(yàn)證中,com.nqzero:permit-reflect用于序列化期間所需的反射函數(shù),而org.apache.httpcomponents.httpclient則被用于將惡意小工具發(fā)送到HTTP服務(wù)。為觸發(fā)這個(gè)漏洞,攻擊者使用Apache Dubbo和JDK的類空間中可用方法設(shè)計(jì)了新的小工具鏈。
此小工具鏈?zhǔn)褂靡韵陆M件:
圖3–利用字節(jié)碼
如果調(diào)用了newTransformer,
HttpInvokerServiceExporter.doReadRemoteInvocation(ObjectInputStream ois)
和java.lang.Runtime.getRuntime().exec(command)之間的反序列化流程就完成了,從而實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行。
最終小工具鏈的結(jié)構(gòu)如下:
如果該漏洞被觸發(fā),并且惡意代碼被執(zhí)行(在概念驗(yàn)證中,服務(wù)器上會(huì)彈出一個(gè)calc.exe實(shí)例),就會(huì)引發(fā)異常。然而,應(yīng)用程序?qū)⒗^續(xù)按照預(yù)期的方式運(yùn)行,從而穩(wěn)定地利用給定的小工具鏈。
圖4–概念驗(yàn)證結(jié)果
為什么會(huì)發(fā)生這種情況?
當(dāng)在Spring框架上使用HTTP協(xié)議創(chuàng)建Dubbo應(yīng)用程序時(shí),就會(huì)出現(xiàn)使用HTTP遠(yuǎn)程處理的Apache Dubbo。Dubbo毫無防備地在Spring中調(diào)用一個(gè)已知存在漏洞的類,并使用極易受攻擊(幾乎沒有防范能力)的ObjectInputStream反序列化用戶輸入。攻擊者可以提供一個(gè)有效負(fù)載,當(dāng)反序列化時(shí),該有效負(fù)載將觸發(fā)一連串的對(duì)象和方法調(diào)用,如果在反序列化范圍內(nèi)給定一個(gè)易受攻擊的小工具鏈,可能會(huì)導(dǎo)致遠(yuǎn)程代碼執(zhí)行,這將在本概念驗(yàn)證中演示。
易受攻擊的Spring Remoting類是HttpInvokerServiceExporter。來自Spring文檔中:
“警告:請(qǐng)當(dāng)心不安全的Java反序列化導(dǎo)致的漏洞問題:在反序列化步驟中,被操縱的輸入流會(huì)導(dǎo)致服務(wù)器上不需要的代碼執(zhí)行。因此,不要將HTTP調(diào)用方端點(diǎn)暴露給不可信的客戶端,而是只在您自己的服務(wù)之間公開。一般來說,我們強(qiáng)烈推薦采用任何其他消息格式替代(如JSON)。”
這正是Dubbo HTTP遠(yuǎn)程處理所發(fā)生的情況。使用Dubbo HTTP遠(yuǎn)程處理模塊,公開一個(gè)接收以下結(jié)構(gòu)的HTTP請(qǐng)求的HTTP端點(diǎn):
HttpProtocol處理程序使用HttpInvokerServiceExporter解析傳入的org.apache.dubbo.rpc.protocol.http.HttpRemoteInvocation對(duì)象,該對(duì)象在內(nèi)部利用ObjectInputStream對(duì)其進(jìn)行反序列化。HttpRemoteInvocation包含對(duì)某個(gè)方法的調(diào)用,以及該方法的傳遞參數(shù)。但是,使用ObjectInputStream,可以傳遞任何任意序列化的Java對(duì)象,然后以不安全的方式反序列化這些對(duì)象,從而導(dǎo)致不安全的反序列化。
ObjectInputStream本身沒有任何外部類,當(dāng)它用于反序列化格式錯(cuò)誤的嵌套對(duì)象時(shí),容易受到內(nèi)存耗盡和堆溢出攻擊。
如果允許代碼或命令執(zhí)行的代碼范圍內(nèi)有ObjectInputStream可反序列化小工具鏈,則攻擊者可以利用這一點(diǎn)來創(chuàng)建導(dǎo)致遠(yuǎn)程代碼執(zhí)行的對(duì)象。這樣一個(gè)小工具鏈被發(fā)現(xiàn)和利用。
受污染的代碼流
在Dubbo HTTP服務(wù)中,會(huì)發(fā)生以下情況:
開發(fā)所需的先驗(yàn)知識(shí)
利用開放的HTTP端口訪問Dubbo HTTP Remoting服務(wù)所需知道的唯一內(nèi)容就是遠(yuǎn)程調(diào)用(Remote Invocation)接口的程序包和類的名稱。該信息用于創(chuàng)建URL,后者是序列化惡意對(duì)象必須提交的地方,這是標(biāo)準(zhǔn)Spring bean行為。舉例而言,如果遠(yuǎn)程接口的程序包名稱為“org.apache.dubbo.demo”,而被遠(yuǎn)程處理的接口名稱為“DemoService”,則攻擊者需要將由ObjectOutputStream序列化的對(duì)象發(fā)布到URL“http://domain:port/org.apache.dubbo.demo.DemoService”上。這些URL信息可以以下各種方法獲得:
執(zhí)行攻擊不需要額外的信息。
應(yīng)該注意的是,人們一般不會(huì)將URL路徑視為機(jī)密信息,但網(wǎng)絡(luò)攻擊者可以在所謂的不可知的URL路徑后面隱藏易受攻擊的網(wǎng)絡(luò)服務(wù),通過隱蔽性的操作,對(duì)服務(wù)安全構(gòu)成威脅。
時(shí)間軸和披露信息總結(jié)
Checkmarx研究團(tuán)隊(duì)首次發(fā)現(xiàn)這個(gè)漏洞后,致力于找到能夠再現(xiàn)漏洞攻擊進(jìn)程的方法。一旦證實(shí)攻擊者的漏洞攻擊方法,研究團(tuán)隊(duì)就會(huì)負(fù)責(zé)任地將自己的研究發(fā)現(xiàn)告知Apache。
披露時(shí)間軸
程序包版本
org.apache.dubbo.dubbo – 2.7.3
org.apache.dubbo.dubbo-remoting-http – 2.7.3
org.springframework.spring-web – 5.1.9.RELEASE
供應(yīng)商防范
Apache Dubbo團(tuán)隊(duì)通過將FastJSON(含最新版本JSONObject)更新為項(xiàng)目依賴項(xiàng)中的最新版本,解決了這個(gè)問題,有效地打破了當(dāng)前的枷鎖。他們還將HTTP協(xié)議使用的反序列化機(jī)制進(jìn)行替換,變更了通信協(xié)議,確保這種特定的攻擊無法發(fā)揮作用。
結(jié)論
Dubbo HTTP Remoting服務(wù)容易受到未經(jīng)認(rèn)證的遠(yuǎn)程代碼執(zhí)行的攻擊。事實(shí)上,攻擊者除了需要知道URL的信息,不需要知道任何先驗(yàn)知識(shí)就可以順利通過該漏洞對(duì)該服務(wù)進(jìn)行攻擊。
造成這種漏洞問題的根本原因是系統(tǒng)使用了一個(gè)不安全的Spring類,HttpInvokerServiceExporter,用于綁定HTTP服務(wù)。該類使用標(biāo)準(zhǔn)的Java ObjectStream,并且沒有白名單類形式的安全機(jī)制,卻能讓反序列化允許調(diào)用其反序列化過程可能觸發(fā)惡意代碼的任意類。這時(shí)應(yīng)該停止使用這個(gè)類,采用完善的解決方案替代,將DubboHTTP beans中的預(yù)期類列入白名單。
Checkmarx安全研究團(tuán)隊(duì)持續(xù)開展這類研究活動(dòng)旨在讓全球各地的企業(yè)都能在軟件安全實(shí)踐方面進(jìn)行必要的變革,以努力提高所有人的整體安全防護(hù)級(jí)別。了解更多安全研究可以關(guān)注Checkmarx微信公眾號(hào)和官網(wǎng)。
附件1
附件1A:DubboGadget類
一個(gè)用于攻擊Dubbo HTTP實(shí)例的類
附件1B: Utils類
實(shí)用類,包括實(shí)用方法,用于創(chuàng)建惡意小工具鏈的某些部分,并通過簡(jiǎn)化反射來公開某些函數(shù)。很大程度上,實(shí)用類源自Chris Frohoff系列文章中的輔助類和舒適方法——https://github.com/frohoff/ysoserial。此外,makeXStringToStringTrigger源自Moritz Bechler的前期研究,示例參見https://github.com/mbechler/marshalsec
附件1C:用于DubboGadget的pom.xml文件
DubboGadget的Maven依賴項(xiàng)