從Blind XXE漏洞到讀取Root檔案的系統提權
在最近的漏洞眾測過程中,作者測試XXE漏洞時,遇到了一個有意思的XML服務端。該服務端在網上基本沒什麼記錄和參考,唯一能找到相關的,只是一篇2016年初,某開發人員應用該服務端遇到困難時,尋求幫助的發貼。在以下文章中,作者分享了測試該服務端時的一些思路,最終,作者利用了一箇中危漏洞的Blind XXE,發現了可讀取root級別檔案的高危漏洞,成功實現了系統提權。
文中刻意著重描述了測試過程中遇到的各種錯誤訊息,希望對讀者有所啟發和幫助。另外,由於是邀請測試,出於保密,其中所有涉及服務端的可識別資訊都已了作了隱匿處理。
一開始的發現
起初,引起我注意的是一個響應XML格式訊息和404狀態的服務端,如下:
但當我把請求方法更改為POST,且在其中添加了一個 Content-Type: application/xml 這樣的頭,和一個無效的XML內容體,之後,響應訊息多了一些有意思的變化,看似有點XXE的意思:
然而,當新增進入的是一個正常結構的XML文件之後,響應訊息有了更進一步的變化:
請注意,服務端顯然希望提供密碼或憑據資訊才能與其進行正常互動,遺憾的是,當前專案沒有任何文件提及憑據的具體形式,而且我也沒找到任何有效的憑據資訊。確實,之前我做過的一些XXE利用方式需要與目標服務端進行某些形式的“有效”互動,才能成功起效。所以,現在看來,沒有憑據,想要深入利用XXE漏洞就非常難了。
但是,雖然如此,我們也不必灰心。由於XML文件結構包括XML宣告、DTD文件型別定義和文件元素資訊,所以這裡我們可以來測試一下 DOCTYPE 定義,看看服務端是否完全禁用了外部實體的應用,或者試試其它有什麼響應。所以,我又接著構造了以下包含DOCTYPE,且利用了Collaborator模組進行帶外測試的請求,並有了相應響應:
伺服器無法對您的請求做出及時響應。!?之後,我又仔細在Burp Collaborator中的檢查了相關互動,迫切希望其中能發現一個傳入的HTTP請求,但是隻看到了以下畫面:
非常不幸,服務端貌似可以解析我的burpcollaborator.net代理域名,但卻沒有出現HTTP請求,而且服務端在幾秒之後出現了500的超時響應狀態。
這看似是服務端防火牆的作用了,我繼續針對其它埠進行出站HTTP請求測試,但都無功而返。所有埠都會顯示超時,也就是說目標服務端部署的防火牆能成功阻斷所有非正常出站流量,安全防護做的還不錯嘛!
實現 Blind XXE
基於以上發現,我搗鼓一通,測試發現了一個問題,但還不太確定,我只有通過嘗試訪問一些本地檔案、內部網路或相關服務,來證明它可能會是一箇中危漏洞。
該漏洞問題的影響是,我可以用它來成功探測目標服務端上一些檔案的存在性,如下:
響應訊息說明了檔案的存在可能,而且能被服務端的XML解析器正常開啟讀取,但由於檔案內容不是一個有效的XML文件型別定義,所以解析器解析失敗並丟擲了一個錯誤。換句話說,服務端未禁用外部實體的載入,但我們卻沒看到任何輸出資訊,所以,從這個角度來說,這看似是一個Blind XXE漏洞。
此外,我們可以假設服務端執行的解析器是 Java 的 SAX解析器,因為從響應報錯訊息來看,它似乎和 Java錯誤類 org.xml.sax.SAXParseExceptionpublicId 相關,這就有意思了,因為Java在XXE方面具備很多特性,之後我們會做講解。
當我們構造訪問的檔案在服務端不存在時,其響應為:
OK,這看似是有用,但還不夠說明問題。我在想,能不能利用這個Blind XXE漏洞開展一些對目標服務端的原始埠探測掃描呢?如下:
這種方法不錯,可行的話證明我們可以枚舉出目標服務端的內部服務,這雖然能反映些許問題,但還不是我想要的效果。這樣的Blind XXE漏洞看似和Blind SSRF漏洞有些相同:可以發起對內部服務的HTTP請求,但卻不能讀取響應。
所以,我就好奇能不能用其它SSRF相關技巧來間接利用這個Blind XXE漏洞呢。先可以做的就是檢視服務端的其它協議使用情況了,如https、gopher、ftp、jar、scp等等,雖然最終對這些協議的測試沒有實質性的效果,但從服務端的錯誤響應訊息中可以得到很多有用資訊。如:
是不是很有意思,服務端能識別我們提供的使用協議,並做出錯誤響應。這個點可以先記下,以備後用。
因為和Blind SSRF漏洞的相似性,所以可以利用它來探測一些內部Web服務。由於這家公司和非常廣泛多樣的開發團隊都有合作,並且在其Github開發文件中也涉及了大量形如x.company.internal樣式的內部主機說明,我發現目標公司部署瞭如下的一些內部服務資源:
wiki.company.internal jira.company.internal confluence.company.internal
由於之前的防火牆阻斷了我的出站流量,在這裡,我想驗證它是否會對內部服務的流量進行阻斷,或是這些內部服務是否真的存在。
從以上響應結果來看很有意思,可以看到報錯訊息說明,我們請求的內部資源被服務端讀取了,只被識別為錯誤格式。也就是說,內部資源的讀取是被允許的,而且我們的請求也是有效的。
這就是厲害所在了,利用Blind XXE漏洞可以發起對目標系統內部Web服務的請求、列舉檔案存在可能、列舉所有可能的執行服務。基於這些危害,我上報了漏洞。但當我週末出外旅行時,我卻一直在思考這個漏洞,覺得應該還有其它深入發現的可能性。
盲人國裡,獨眼稱王
經過一個週末的休整和思路調整,我決定對這個Blind XXE漏洞再繼續深挖。尤其是,我意識到如果我能在目標服務端內部找到類似代理作用的主機,就可以把未做安全過濾的內部服務流量路由到外部來。
常來說,要從無法讀取響應的Web應用中去發現漏洞相當之難,但好在,早前社群披露過 一個針對Jira應用的SSRF漏洞 ,並已在多篇發文中提到過 具體的利用方法 。
為此,我急切地想利用這個方法來映證我在Github上發現的目標公司的Jira應用:jira.company.internal,構造的請求和對應的響應如下:
從響應訊息中可以看到,可能是SSL驗證方式出錯導致了HTTPS請求有問題,另外,通常的Jira例項都是執行在8080埠之上的,那麼,我們就換成HTTP,加上8080埠試試:
然後,我查看了 Burp Collaborator 模組的互動資訊,並沒什麼發現,可能是服務端的Jira例項打了補丁或是禁用了存在漏洞的外掛。之後,我漫無目的地在wiki.company.internal上去找SSRF漏洞,最後,我決定在confluence.company.internal上嘗試一下和jira.company.internal相同的測試方法,只是我把測試埠換成了confluence應用的預設埠8090:
等等,這是什麼?多了一個HTTP請求:
成功了!這樣就可以通過confluence例項,繞過防火牆限制,把內部流量間接轉向外部了。也就意味著,我們可以在上面進行一些經典的XXE攻擊了。首先,我們構造出一個如下內容的惡意檔案evil.xml,並把其託管在攻擊者伺服器上,希望最終能觸發出有用的資訊來。
<!ENTITY % file SYSTEM "file:///"> <!ENTITY % ent "<!ENTITY data SYSTEM '%file;'>">
讓我們來仔細看看上面這個檔案的具體定義:
1、把外部引用(這裡是系統的/目錄)載入到變數%file中來; 2、定義一個%ent變數,它只是起到一個穿插作用,目的在於編譯第三個實體定義; 3、嘗試在%file處訪問資源,並將該位置的內容載入到實體的data中。
注意,我們希望上述第3方面的定義執行失效,因為%file處的內容將不會指向一個有效的資源位置,而只是會包含完整的目錄內容。
現在,利用confluence.company.internal這個內部例項來指向我們的惡意檔案evil.xml,並要保證其中的 %ent 和 &data 要能被訪問到,以觸發目錄訪問。太好了,響應最終列出了服務端的所有目錄資訊:
有意思的是,這顯示了另一種從服務端獲取錯誤響應的方法,即指定一個“missing”丟失的協議,而不是我們前面看到的無效協議。這也可幫助我們解決在讀取包含冒號的檔案時遇到的問題,例如用上述方法讀取/etc/passwd時會導致以下錯誤:
換句話說,第一次出現在冒號:之前,是可以讀取檔案的,但冒號之後的東西就不能再被讀取了。如何來繞過這一點並在響應訊息中顯示具體檔案內容呢?那就是在檔案內容之前加上一個冒號,這會導致出現“no protocol”錯誤,因為首個冒號之前的欄位是空的,如未定義樣式。所以,我們在攻擊者伺服器上的託管檔案 evil.xml 可構造如下:
<!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">
最終的結果如下:
讀取/root目錄檔案的結果:
就這樣,針對目標公司系統,通過濫用不當的網路隔離措施、未打補丁的內部應用服務、未作許可權配置的Web伺服器和存在資訊洩露的錯誤響應,我們就能從Blind XXE的中危漏洞,提權至可讀取root級別檔案的高危漏洞,實現了對目標系統的控制。