張 晨
(廈門軟件職業(yè)技術(shù)學(xué)院 軟件工程系,福建 廈門 361024)
關(guān)鍵字:網(wǎng)絡(luò)安全 漏洞分析 Web安全 Java反序列化
Java Web是用Java技術(shù)來解決相關(guān)web互聯(lián)網(wǎng)領(lǐng)域的技術(shù)棧[1],其在Web技術(shù)的基礎(chǔ)上融合了Java語言的優(yōu)勢特點,是目前大型企業(yè)或者政府部門進行Web系統(tǒng)開發(fā)的主流方式。在互聯(lián)網(wǎng)發(fā)展浪潮的背景下,Java Web以簡單易用的特點成為互聯(lián)網(wǎng)不可或缺的重要功能載體,但隨之而來的相關(guān)網(wǎng)絡(luò)安全問題成為了不得不面對的難題,根據(jù)Akamai的通報,每年針對Web應(yīng)用程序的攻擊數(shù)量居高不下,網(wǎng)絡(luò)攻擊的手段也呈現(xiàn)出了多樣化的情況,其中不安全的反序列化、開源組件風(fēng)險、SQL注入漏洞、XSS漏洞是產(chǎn)生網(wǎng)絡(luò)安全威脅的主要因素。在OWASP(開放式Web應(yīng)用程序安全項目)組織發(fā)布的2021年全球十大Web應(yīng)用安全中[2],不安全設(shè)計(Insecure Design)和自帶缺陷和過時的組件(Vulnerable and Outdated Components)榜上有名。
不存在完美的編程語言,并且任何系統(tǒng)和應(yīng)用的安全性都不是絕對的,Java Web程序的安全問題也是不可避免的,一些看似合理的功能邏輯卻常常有可能存在著可被非法利用的漏洞,如Java的反序列化機制所引發(fā)的反序列化漏洞問題。
Java序列化和反序列化的初衷是為了有效實現(xiàn)對象在不同系統(tǒng)和進程之間的數(shù)據(jù)快速傳輸和方便存儲[3]。為了滿足java的序列化與反序列化的需求,在開發(fā)過程中通常需要使用到一些公共庫,Apache Commons Collections 便是其中之一,該庫不僅能夠提供數(shù)據(jù)結(jié)構(gòu)類型還包含了許多jar工具和接口。作為Apache開源項目的重要組件,Commons Collections已被廣泛應(yīng)用于各種Java Web應(yīng)用的開發(fā),據(jù)國家網(wǎng)絡(luò)安全漏洞共享平臺(CNVD)收錄的Apache Commons Components Invoker Transformer反序列化任意代碼執(zhí)行高危漏洞(編號為CNVD-2015-07556)顯示[4],代碼設(shè)計或自帶缺陷以及陳舊的組件將導(dǎo)致反序列化漏洞的存在,相關(guān)漏洞影響到了WebLogic、JBoss、Jenkins、WebSphere、OpenNMS等諸多Web應(yīng)用和中間件。雖然Apache Commons Collections不斷推陳出新,各大應(yīng)用廠商也陸續(xù)發(fā)布升級補丁,但網(wǎng)絡(luò)上還有很多Web站點和應(yīng)用受到此漏洞的影響。
反序列化漏洞的本質(zhì)是一種對象化注入漏洞,常常會被非法利用于代碼復(fù)用攻擊。分析Java Web序列化與反序列化的機制:首先序列化的過程是將對象轉(zhuǎn)換成包含該對象的數(shù)據(jù)、類型等狀態(tài)信息的字節(jié)序列用來進行數(shù)據(jù)的傳輸和存儲,即通過ObjectOutputStream類的writeObject()方法對參數(shù)指定的對象序列化的數(shù)據(jù)寫入到一個目標(biāo)輸出流之中。而后再利用反序列化這一逆過程,通過ObjectInputStream類的readObject()方法從一個源輸入流中讀取字節(jié)序列,并還原轉(zhuǎn)換成為對象。通常,序列化后的對象可以通過反序列化方法在其他平臺上利用對象的類型信息、數(shù)據(jù)、數(shù)據(jù)類型在內(nèi)存中完成對象的新建。反序列化適用于Java Web下的大量應(yīng)用場景,例如在Web服務(wù)器的物理硬盤中暫存用戶訪問的Session對象,保證用戶信息不丟失,并有效騰挪服務(wù)器的內(nèi)存資源來提高相關(guān)業(yè)務(wù)的可用性。
Java的序列化和反序列化設(shè)計的初衷并不存在問題,但如果存在代碼設(shè)計缺陷,例如ObjectInputStream類的readObject()方法內(nèi)的代碼邏輯缺陷,則可能會存在反序列化漏洞。當(dāng)被非法利用時,惡意構(gòu)造的數(shù)據(jù)被植入到了反序列化進程,而后又由于類庫未對序列化對象作相關(guān)的檢查或限制,就將導(dǎo)致沒有經(jīng)過檢測而產(chǎn)生的對象執(zhí)行任意非法的RCE(Remote command/Code execute,遠程命令/代碼執(zhí)行)代碼,從而出現(xiàn)各種危害系統(tǒng)的操作被執(zhí)行的情況。Apache Commons Collections組件漏洞的問題主要出現(xiàn)在org.apache.commons.collections.Transformer接口上,產(chǎn)生的根本原因在于對數(shù)據(jù)缺乏檢測與過濾的機制,這就造成在進行反序列化操作時不會調(diào)用構(gòu)造函數(shù)對生成對象的類型進行檢測與校驗的結(jié)果。并且組件中的特殊接口類InvokerTransformer可以調(diào)用Java的反射機制來執(zhí)行一些函數(shù)函數(shù)或特定的命令以及SQL語句等。Java反序列化漏洞廣泛存在于Java Web中,只要包含了Commons Collections的jar包,無論源碼是否使用到了組件中的類,都存在遠程代碼被執(zhí)行的風(fēng)險。
以Commons Collections6為例(以下簡稱CC6)對Java Web反序列化利用鏈進行分析:CC6的命令執(zhí)行載體為org.apache.commons. collections. functors.ChainedTransformer函數(shù),反序列化對象為HashMap,反序列化集合載體為HashSet。如圖1所示為漏洞的利用鏈,CC6利用鏈?zhǔn)抢肏ashSet來觸發(fā)LazyMap的get方法,即HashSet.readObject()完成元素的反序列化后,會調(diào)用HashMap.put()將結(jié)果放進去,當(dāng)通過 TiedMapEntry.hashCode()計算hash時,會調(diào)用getValue()觸發(fā)LazyMap.get(),從而導(dǎo)致相關(guān)目標(biāo)命令的執(zhí)行。
圖1 CC6的利用鏈
由于反序列化漏洞都需要用到程序中存在的已知類,因此查找存在安全漏洞的類很重要。反序列化代碼審計需要從Java Web應(yīng)用的本身以及應(yīng)用與Web服務(wù)器之間的組件所涉及到的序列化對象入手檢查,要定位出應(yīng)用的源碼中哪些是調(diào)用了反序列化函數(shù)的代碼。同時,序列化內(nèi)容都需要遵從序列化協(xié)議,分析反序列數(shù)據(jù)特征,Java序列化后的數(shù)據(jù)包開頭部分通常是一個雙字節(jié)的魔法數(shù)字0xACED。定位的過程可以使用Wireshark等工具對數(shù)據(jù)包進行分析,查看數(shù)據(jù)包是否包含以“AC ED 00 05”標(biāo)記開頭的序列化數(shù)據(jù),再進一步審計目標(biāo)應(yīng)用Class Path中的Apache Commons Collections庫相關(guān)代碼[5]。
通常一個完整的漏洞包括已知原生反序列化源方法(source)和觸發(fā)漏洞的目標(biāo)方法(sink)的鏈?zhǔn)秸{(diào)用。source作為引入點可能會獲取外部不可信的輸入數(shù)據(jù)并返回,再通過遞歸檢查尋找一條調(diào)用鏈(gadget)進行傳播,最后在目標(biāo)sink觸發(fā)執(zhí)行。代碼審計分析的過程需要判斷在sources和sinks之間是否存在一條可達的利用路徑。Java Web反序列化漏洞利用的常常是在目標(biāo)Web應(yīng)用中找到一個可接收外部輸入的序列化對象的反序列化接收點,再利用反序列化的payload針對目標(biāo)應(yīng)用進行注入,來觸發(fā)ObjectInputStream 的反序列化操作,并通過反射調(diào)用RunTime.exec從而實現(xiàn)對漏洞的利用。因此Java Web的代碼審計要先檢查找到HashSet.readObject、Fastjson等反序列化入口,再探尋調(diào)用鏈,從而找到LazyMap.get()、Runtime.exec等觸發(fā)漏洞的目標(biāo)方法。
如表1和表2所示為序列化和反序列化函數(shù)的使用實例:從“user.bin”二進制文件中讀取數(shù)據(jù),并對其進行反序列化。在該實例中如果未設(shè)置檢查和過濾機制,并且“user.bin”的文件內(nèi)容是用戶可控的,即用戶可以修改內(nèi)容的輸入,那么可能會存在反序列化漏洞。
表1 序列化serialization函數(shù)使用實例
表2 反序列化unserialization函數(shù)使用實例
反序列化的一系列的變換操作,是通過定義一個ChainedTransformer來實現(xiàn)的。對commons collections中利用的類進行分析,在該組件中有一個Transformer接口。通過傳入一個Transformer數(shù)組即可定義一個ChainedTransformer來實現(xiàn)一系列的變換操作。表3為漏洞利用代碼,commons collections組件中InvokerTransformer是實現(xiàn)Transformer接口的類。RunTime類常用于調(diào)用外部程序,將可能被用于執(zhí)行RCE。要找到調(diào)用了Transform方法的節(jié)點,可以通過ReadObject入手,再順著利用鏈一步步分析定位。
表3 CC6的利用示例
網(wǎng)絡(luò)安全漏洞難以避免,采用安全技術(shù)手段也無法將其完全清除,但是使用合理有效的防范方法能夠降低網(wǎng)絡(luò)安全風(fēng)險,保證Web互聯(lián)網(wǎng)程序更加正常和穩(wěn)定的運行[6]。針對Java Web的網(wǎng)絡(luò)安全問題,應(yīng)當(dāng)在站點和程序的規(guī)劃設(shè)計階段就將各種可能產(chǎn)生漏洞的因素考慮進去,在開發(fā)階段和后期維護階段還要不斷進行代碼審計、測試驗證。做到以下幾點來保證客戶端和服務(wù)端的安全:
在站點程序設(shè)計、開發(fā)建設(shè)階段和后期的維護過程都需要分析Java Web反序列化漏洞具體形成原因,有針對性地關(guān)注具體應(yīng)用中的可序列化類,開展相關(guān)應(yīng)用的安全性檢查,通過代碼審計和行為分析等手段發(fā)現(xiàn)站點漏洞所在的靶點[7]。需要關(guān)注相關(guān)廠家官方的補丁發(fā)布情況及時進行升級,定期對站點的基礎(chǔ)庫進行安全性檢查。定期采用白盒與黑盒相結(jié)合的方式進行站點漏洞測試,對程序執(zhí)行動態(tài)檢測,通過動態(tài)檢測對運行的程序進行網(wǎng)絡(luò)安全測試,再對比靜態(tài)分析結(jié)果可以進一步確認漏洞點,并且還可以發(fā)現(xiàn)其他潛在的威脅漏洞。加強對Runtime.exec等相關(guān)代碼的檢測,并對存在風(fēng)險的應(yīng)用及時進行代碼安全加固。
做好文件、接口、協(xié)議等細節(jié)問題的優(yōu)化,在保證功能和業(yè)務(wù)正常運行的前提下,刪除存在風(fēng)險的文件、停用非必要的接口,如禁止JVM執(zhí)行外部命令和程序。關(guān)注敏感信息的加密,確保對象的成員變量符合正確的約束條件。對于HTTP請求中的cookies、Parameters和RMI遠程調(diào)用接口、JMX擴展接口等基于序列化操作的接口及協(xié)議開展監(jiān)測。合理并有效使用加密功能進行加密存儲。設(shè)計嚴格的訪問和認證的機制,利用數(shù)字簽名、數(shù)字證書等方式完成身份認證,防止程序代碼的泄露及不合法的程序復(fù)制。反序列化漏洞被利用時,通常攻擊者會通過如文件上傳、SQL注入、XSS利用等手段上傳一個webshell來進一步入侵系統(tǒng),從而達到遠程執(zhí)行命令、操作敏感信息的目的,因此要加強系統(tǒng)入侵檢測。另外,還可以利用蜜罐系統(tǒng),來偵測異常行為和隱藏真實的程序系統(tǒng)。
全球的網(wǎng)絡(luò)安全技術(shù)一直在不斷的變化和發(fā)展,網(wǎng)絡(luò)攻擊的發(fā)起者與系統(tǒng)開發(fā)者以及網(wǎng)絡(luò)安全防御者也始終處于彼此博弈的狀態(tài)之中。作為系統(tǒng)開發(fā)和維護人員不能僅僅將目光局限在系統(tǒng)的開發(fā)和功能需求的實現(xiàn)上,在網(wǎng)絡(luò)安全已上升到國家高度的背景下,更需要加強網(wǎng)絡(luò)安全知識的學(xué)習(xí),及時關(guān)注全球網(wǎng)絡(luò)安全態(tài)勢、了解最新的網(wǎng)絡(luò)安全事件和主要的網(wǎng)絡(luò)攻擊手段,不斷精進開發(fā)技術(shù)。圍繞Java Web站點的開發(fā)工作,從系統(tǒng)功能、網(wǎng)絡(luò)安全等多角度來分析、完善和提升相關(guān)程序的安全防御性能,保障網(wǎng)絡(luò)安全。
信息化時代,互聯(lián)網(wǎng)數(shù)據(jù)呈現(xiàn)爆炸式的增長,隨著《個人信息保護法》的施行,對于互聯(lián)網(wǎng)個人信息的保護也上升到了一個新的高度。在信息全球化發(fā)展的背景下,網(wǎng)絡(luò)黑客無處不在,因應(yīng)用系統(tǒng)存在漏洞,而造成個人信息泄露或經(jīng)濟損失等事件層出不窮。反序列化的漏洞存在于許多編程語言之中,是近些年出現(xiàn)較為頻繁的高危漏洞之一,也成為應(yīng)用安全研究的熱點之一。在Java Web中由于 Apache Commons Collections庫組件的廣泛使用加上該組件未能對用戶數(shù)據(jù)做出有效過濾,導(dǎo)致攻擊者可以在對象屬性中構(gòu)造惡意代碼進而控制服務(wù)器[8]。基于此,本文對序列化和反序列化的過程展開分析,通過對Java Web反序列化漏洞形成原因及利用原理的研究,提出反序列代碼審計和安全檢查的的基本思路以及漏洞的防范方法,以幫助開發(fā)和運維人員提升相關(guān)程序的安全性,提高業(yè)務(wù)系統(tǒng)的防護水平。